Compare commits
5 Commits
wip/yaak-p
...
gschier/cl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2439ffd28c | ||
|
|
ad31755dbb | ||
|
|
b01b3a4c57 | ||
|
|
ef63b88710 | ||
|
|
fb5ad8c7f7 |
@@ -6,14 +6,14 @@ Make Yaak runnable as a standalone CLI without Tauri as a dependency. The core R
|
||||
## Project Structure
|
||||
```
|
||||
crates/ # Core crates - should NOT depend on Tauri
|
||||
crates-tauri/ # Tauri-specific crates (yaak-app-client, yaak-tauri-utils, etc.)
|
||||
crates-tauri/ # Tauri-specific crates (yaak-app, yaak-tauri-utils, etc.)
|
||||
crates-cli/ # CLI crate (yaak-cli)
|
||||
```
|
||||
|
||||
## Completed Work
|
||||
|
||||
### 1. Folder Restructure
|
||||
- Moved Tauri-dependent app code to `crates-tauri/yaak-app-client/`
|
||||
- Moved Tauri-dependent app code to `crates-tauri/yaak-app/`
|
||||
- Created `crates-tauri/yaak-tauri-utils/` for shared Tauri utilities (window traits, api_client, error handling)
|
||||
- Created `crates-cli/yaak-cli/` for the standalone CLI
|
||||
|
||||
@@ -43,13 +43,13 @@ crates-cli/ # CLI crate (yaak-cli)
|
||||
3. Move extension traits (e.g., `SomethingManagerExt`) to yaak-app or yaak-tauri-utils
|
||||
4. Initialize managers in yaak-app's `.setup()` block
|
||||
5. Remove `tauri` from Cargo.toml dependencies
|
||||
6. Update `crates-tauri/yaak-app-client/capabilities/default.json` to remove the plugin permission
|
||||
6. Update `crates-tauri/yaak-app/capabilities/default.json` to remove the plugin permission
|
||||
7. Replace `tauri::async_runtime::block_on` with `tokio::runtime::Handle::current().block_on()`
|
||||
|
||||
## Key Files
|
||||
- `crates-tauri/yaak-app-client/src/lib.rs` - Main Tauri app, setup block initializes managers
|
||||
- `crates-tauri/yaak-app-client/src/commands.rs` - Migrated Tauri commands
|
||||
- `crates-tauri/yaak-app-client/src/models_ext.rs` - Database plugin and extension traits
|
||||
- `crates-tauri/yaak-app/src/lib.rs` - Main Tauri app, setup block initializes managers
|
||||
- `crates-tauri/yaak-app/src/commands.rs` - Migrated Tauri commands
|
||||
- `crates-tauri/yaak-app/src/models_ext.rs` - Database plugin and extension traits
|
||||
- `crates-tauri/yaak-tauri-utils/src/window.rs` - WorkspaceWindowTrait for window state
|
||||
- `crates/yaak-models/src/lib.rs` - Contains `init_standalone()` for CLI usage
|
||||
|
||||
@@ -68,5 +68,5 @@ e718a5f1 Refactor models_ext to use init_standalone from yaak-models
|
||||
|
||||
## Testing
|
||||
- Run `cargo check -p <crate>` to verify a crate builds without Tauri
|
||||
- Run `npm run client:dev` to test the Tauri app still works
|
||||
- Run `npm run app-dev` to test the Tauri app still works
|
||||
- Run `cargo run -p yaak-cli -- --help` to test the CLI
|
||||
|
||||
4
.gitattributes
vendored
@@ -1,5 +1,5 @@
|
||||
crates-tauri/yaak-app-client/vendored/**/* linguist-generated=true
|
||||
crates-tauri/yaak-app-client/gen/schemas/**/* linguist-generated=true
|
||||
crates-tauri/yaak-app/vendored/**/* linguist-generated=true
|
||||
crates-tauri/yaak-app/gen/schemas/**/* linguist-generated=true
|
||||
**/bindings/* linguist-generated=true
|
||||
crates/yaak-templates/pkg/* linguist-generated=true
|
||||
|
||||
|
||||
8
.github/workflows/release-app.yml
vendored
@@ -122,8 +122,8 @@ jobs:
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
# Sign vendored binaries with hardened runtime and their specific entitlements
|
||||
codesign --force --options runtime --entitlements crates-tauri/yaak-app-client/macos/entitlements.yaakprotoc.plist --sign "$APPLE_SIGNING_IDENTITY" crates-tauri/yaak-app-client/vendored/protoc/yaakprotoc || true
|
||||
codesign --force --options runtime --entitlements crates-tauri/yaak-app-client/macos/entitlements.yaaknode.plist --sign "$APPLE_SIGNING_IDENTITY" crates-tauri/yaak-app-client/vendored/node/yaaknode || true
|
||||
codesign --force --options runtime --entitlements crates-tauri/yaak-app/macos/entitlements.yaakprotoc.plist --sign "$APPLE_SIGNING_IDENTITY" crates-tauri/yaak-app/vendored/protoc/yaakprotoc || true
|
||||
codesign --force --options runtime --entitlements crates-tauri/yaak-app/macos/entitlements.yaaknode.plist --sign "$APPLE_SIGNING_IDENTITY" crates-tauri/yaak-app/vendored/node/yaaknode || true
|
||||
|
||||
- uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
releaseBody: "[Changelog __VERSION__](https://yaak.app/blog/__VERSION__)"
|
||||
releaseDraft: true
|
||||
prerelease: true
|
||||
args: "${{ matrix.args }} --config ./crates-tauri/yaak-app-client/tauri.release.conf.json"
|
||||
args: "${{ matrix.args }} --config ./crates-tauri/yaak-app/tauri.release.conf.json"
|
||||
|
||||
# Build a per-machine NSIS installer for enterprise deployment (PDQ, SCCM, Intune)
|
||||
- name: Build and upload machine-wide installer (Windows only)
|
||||
@@ -168,7 +168,7 @@ jobs:
|
||||
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: |
|
||||
Get-ChildItem -Recurse -Path target -File -Filter "*.exe.sig" | Remove-Item -Force
|
||||
npx tauri bundle ${{ matrix.args }} --bundles nsis --config ./crates-tauri/yaak-app-client/tauri.release.conf.json --config '{"bundle":{"createUpdaterArtifacts":true,"windows":{"nsis":{"installMode":"perMachine"}}}}'
|
||||
npx tauri bundle ${{ matrix.args }} --bundles nsis --config ./crates-tauri/yaak-app/tauri.release.conf.json --config '{"bundle":{"createUpdaterArtifacts":true,"windows":{"nsis":{"installMode":"perMachine"}}}}'
|
||||
$setup = Get-ChildItem -Recurse -Path target -Filter "*setup*.exe" | Select-Object -First 1
|
||||
$setupSig = "$($setup.FullName).sig"
|
||||
$dest = $setup.FullName -replace '-setup\.exe$', '-setup-machine.exe'
|
||||
|
||||
6
.github/workflows/release-cli-npm.yml
vendored
@@ -45,8 +45,8 @@ jobs:
|
||||
with:
|
||||
name: vendored-assets
|
||||
path: |
|
||||
crates-tauri/yaak-app-client/vendored/plugin-runtime/index.cjs
|
||||
crates-tauri/yaak-app-client/vendored/plugins
|
||||
crates-tauri/yaak-app/vendored/plugin-runtime/index.cjs
|
||||
crates-tauri/yaak-app/vendored/plugins
|
||||
if-no-files-found: error
|
||||
|
||||
build-binaries:
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: vendored-assets
|
||||
path: crates-tauri/yaak-app-client/vendored
|
||||
path: crates-tauri/yaak-app/vendored
|
||||
|
||||
- name: Set CLI build version
|
||||
shell: bash
|
||||
|
||||
3
.gitignore
vendored
@@ -39,8 +39,7 @@ codebook.toml
|
||||
target
|
||||
|
||||
# Per-worktree Tauri config (generated by post-checkout hook)
|
||||
crates-tauri/yaak-app-client/tauri.worktree.conf.json
|
||||
crates-tauri/yaak-app-proxy/tauri.worktree.conf.json
|
||||
crates-tauri/yaak-app/tauri.worktree.conf.json
|
||||
|
||||
# Tauri auto-generated permission files
|
||||
**/permissions/autogenerated
|
||||
|
||||
101
Cargo.lock
generated
@@ -477,28 +477,6 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
"dunce",
|
||||
"fs_extra",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.7.9"
|
||||
@@ -2214,12 +2192,6 @@ dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "4.1.0"
|
||||
@@ -5143,16 +5115,6 @@ dependencies = [
|
||||
"hmac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.2"
|
||||
@@ -5993,19 +5955,6 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rcgen"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
|
||||
dependencies = [
|
||||
"pem",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"time",
|
||||
"yasna",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.12"
|
||||
@@ -6739,8 +6688,6 @@ version = "0.23.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"log 0.4.29",
|
||||
"once_cell",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -6813,7 +6760,6 @@ version = "0.103.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
"untrusted",
|
||||
@@ -10240,7 +10186,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-app-client"
|
||||
name = "yaak-app"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"charset",
|
||||
@@ -10297,23 +10243,9 @@ dependencies = [
|
||||
"yaak-tauri-utils",
|
||||
"yaak-templates",
|
||||
"yaak-tls",
|
||||
"yaak-window",
|
||||
"yaak-ws",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-app-proxy"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"log 0.4.29",
|
||||
"serde",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-os",
|
||||
"yaak-proxy",
|
||||
"yaak-window",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-cli"
|
||||
version = "0.1.0"
|
||||
@@ -10554,23 +10486,6 @@ dependencies = [
|
||||
"zip-extract",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-proxy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper-util",
|
||||
"pem",
|
||||
"rcgen",
|
||||
"rustls",
|
||||
"rustls-native-certs",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-sse"
|
||||
version = "0.1.0"
|
||||
@@ -10636,17 +10551,6 @@ dependencies = [
|
||||
"yaak-models",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-window"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log 0.4.29",
|
||||
"md5 0.8.0",
|
||||
"rand 0.9.1",
|
||||
"tauri",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaak-ws"
|
||||
version = "0.1.0"
|
||||
@@ -10678,9 +10582,6 @@ name = "yasna"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
|
||||
dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
@@ -17,17 +17,14 @@ members = [
|
||||
"crates/yaak-tls",
|
||||
"crates/yaak-ws",
|
||||
"crates/yaak-api",
|
||||
"crates/yaak-proxy",
|
||||
# CLI crates
|
||||
"crates-cli/yaak-cli",
|
||||
# Tauri-specific crates
|
||||
"crates-tauri/yaak-app-client",
|
||||
"crates-tauri/yaak-app-proxy",
|
||||
"crates-tauri/yaak-app",
|
||||
"crates-tauri/yaak-fonts",
|
||||
"crates-tauri/yaak-license",
|
||||
"crates-tauri/yaak-mac-window",
|
||||
"crates-tauri/yaak-tauri-utils",
|
||||
"crates-tauri/yaak-window",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
@@ -66,14 +63,12 @@ yaak-templates = { path = "crates/yaak-templates" }
|
||||
yaak-tls = { path = "crates/yaak-tls" }
|
||||
yaak-ws = { path = "crates/yaak-ws" }
|
||||
yaak-api = { path = "crates/yaak-api" }
|
||||
yaak-proxy = { path = "crates/yaak-proxy" }
|
||||
|
||||
# Internal crates - Tauri-specific
|
||||
yaak-fonts = { path = "crates-tauri/yaak-fonts" }
|
||||
yaak-license = { path = "crates-tauri/yaak-license" }
|
||||
yaak-mac-window = { path = "crates-tauri/yaak-mac-window" }
|
||||
yaak-tauri-utils = { path = "crates-tauri/yaak-tauri-utils" }
|
||||
yaak-window = { path = "crates-tauri/yaak-window" }
|
||||
|
||||
[profile.release]
|
||||
strip = false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/JamesIves/github-sponsors-readme-action">
|
||||
<img width="200px" src="https://github.com/mountain-loop/yaak/raw/main/crates-tauri/yaak-app-client/icons/icon.png">
|
||||
<img width="200px" src="https://github.com/mountain-loop/yaak/raw/main/crates-tauri/yaak-app/icons/icon.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import deepEqual from "@gilbarbara/deep-equal";
|
||||
import type { UpdateInfo } from "@yaakapp-internal/tauri-client";
|
||||
import type { Atom } from "jotai";
|
||||
import { atom } from "jotai";
|
||||
import { selectAtom } from "jotai/utils";
|
||||
import type { SplitLayoutLayout } from "../components/core/SplitLayout";
|
||||
import { atomWithKVStorage } from "./atoms/atomWithKVStorage";
|
||||
|
||||
export function deepEqualAtom<T>(a: Atom<T>) {
|
||||
return selectAtom(
|
||||
a,
|
||||
(v) => v,
|
||||
(a, b) => deepEqual(a, b),
|
||||
);
|
||||
}
|
||||
|
||||
export const workspaceLayoutAtom = atomWithKVStorage<SplitLayoutLayout>(
|
||||
"workspace_layout",
|
||||
"horizontal",
|
||||
);
|
||||
|
||||
export const updateAvailableAtom = atom<Omit<
|
||||
UpdateInfo,
|
||||
"replyEventId"
|
||||
> | null>(null);
|
||||
@@ -1,322 +0,0 @@
|
||||
import { emit } from "@tauri-apps/api/event";
|
||||
import { openUrl } from "@tauri-apps/plugin-opener";
|
||||
import { debounce } from "@yaakapp-internal/lib";
|
||||
import type {
|
||||
FormInput,
|
||||
InternalEvent,
|
||||
JsonPrimitive,
|
||||
ShowToastRequest,
|
||||
} from "@yaakapp-internal/plugins";
|
||||
import { updateAllPlugins } from "@yaakapp-internal/plugins";
|
||||
import type {
|
||||
PluginUpdateNotification,
|
||||
UpdateInfo,
|
||||
UpdateResponse,
|
||||
YaakNotification,
|
||||
} from "@yaakapp-internal/tauri-client";
|
||||
import { openSettings } from "../commands/openSettings";
|
||||
import { Button } from "../components/core/Button";
|
||||
import { ButtonInfiniteLoading } from "../components/core/ButtonInfiniteLoading";
|
||||
import { Icon } from "@yaakapp-internal/ui";
|
||||
import { HStack, VStack } from "../components/core/Stacks";
|
||||
|
||||
// Listen for toasts
|
||||
import { listenToTauriEvent } from "../hooks/useListenToTauriEvent";
|
||||
import { updateAvailableAtom } from "./atoms";
|
||||
import { stringToColor } from "./color";
|
||||
import { generateId } from "./generateId";
|
||||
import { jotaiStore } from "./jotai";
|
||||
import { showPrompt } from "./prompt";
|
||||
import { showPromptForm } from "./prompt-form";
|
||||
import { invokeCmd } from "./tauri";
|
||||
import { showToast } from "./toast";
|
||||
|
||||
export function initGlobalListeners() {
|
||||
listenToTauriEvent<ShowToastRequest>("show_toast", (event) => {
|
||||
showToast({ ...event.payload });
|
||||
});
|
||||
|
||||
listenToTauriEvent("settings", () => openSettings.mutate(null));
|
||||
|
||||
// Track active dynamic form dialogs so follow-up input updates can reach them
|
||||
const activeForms = new Map<string, (inputs: FormInput[]) => void>();
|
||||
|
||||
// Listen for plugin events
|
||||
listenToTauriEvent<InternalEvent>(
|
||||
"plugin_event",
|
||||
async ({ payload: event }) => {
|
||||
if (event.payload.type === "prompt_text_request") {
|
||||
const value = await showPrompt(event.payload);
|
||||
const result: InternalEvent = {
|
||||
id: generateId(),
|
||||
replyId: event.id,
|
||||
pluginName: event.pluginName,
|
||||
pluginRefId: event.pluginRefId,
|
||||
context: event.context,
|
||||
payload: {
|
||||
type: "prompt_text_response",
|
||||
value,
|
||||
},
|
||||
};
|
||||
await emit(event.id, result);
|
||||
} else if (event.payload.type === "prompt_form_request") {
|
||||
if (event.replyId != null) {
|
||||
// Follow-up update from plugin runtime — update the active dialog's inputs
|
||||
const updateInputs = activeForms.get(event.replyId);
|
||||
if (updateInputs) {
|
||||
updateInputs(event.payload.inputs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Initial request — show the dialog with bidirectional support
|
||||
const emitFormResponse = (
|
||||
values: Record<string, JsonPrimitive> | null,
|
||||
done: boolean,
|
||||
) => {
|
||||
const result: InternalEvent = {
|
||||
id: generateId(),
|
||||
replyId: event.id,
|
||||
pluginName: event.pluginName,
|
||||
pluginRefId: event.pluginRefId,
|
||||
context: event.context,
|
||||
payload: {
|
||||
type: "prompt_form_response",
|
||||
values,
|
||||
done,
|
||||
},
|
||||
};
|
||||
emit(event.id, result);
|
||||
};
|
||||
|
||||
const values = await showPromptForm({
|
||||
id: event.payload.id,
|
||||
title: event.payload.title,
|
||||
description: event.payload.description,
|
||||
size: event.payload.size,
|
||||
inputs: event.payload.inputs,
|
||||
confirmText: event.payload.confirmText,
|
||||
cancelText: event.payload.cancelText,
|
||||
onValuesChange: debounce(
|
||||
(values) => emitFormResponse(values, false),
|
||||
150,
|
||||
),
|
||||
onInputsUpdated: (cb) => activeForms.set(event.id, cb),
|
||||
});
|
||||
|
||||
// Clean up and send final response
|
||||
activeForms.delete(event.id);
|
||||
emitFormResponse(values, true);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
listenToTauriEvent<string>(
|
||||
"update_installed",
|
||||
async ({ payload: version }) => {
|
||||
console.log("Got update installed event", version);
|
||||
showUpdateInstalledToast(version);
|
||||
},
|
||||
);
|
||||
|
||||
// Listen for update events
|
||||
listenToTauriEvent<UpdateInfo>("update_available", async ({ payload }) => {
|
||||
console.log("Got update available", payload);
|
||||
showUpdateAvailableToast(payload);
|
||||
});
|
||||
|
||||
listenToTauriEvent<YaakNotification>("notification", ({ payload }) => {
|
||||
console.log("Got notification event", payload);
|
||||
showNotificationToast(payload);
|
||||
});
|
||||
|
||||
// Listen for plugin update events
|
||||
listenToTauriEvent<PluginUpdateNotification>(
|
||||
"plugin_updates_available",
|
||||
({ payload }) => {
|
||||
console.log("Got plugin updates event", payload);
|
||||
showPluginUpdatesToast(payload);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function showUpdateInstalledToast(version: string) {
|
||||
const UPDATE_TOAST_ID = "update-info";
|
||||
|
||||
showToast({
|
||||
id: UPDATE_TOAST_ID,
|
||||
color: "primary",
|
||||
timeout: null,
|
||||
message: (
|
||||
<VStack>
|
||||
<h2 className="font-semibold">Yaak {version} was installed</h2>
|
||||
<p className="text-text-subtle text-sm">
|
||||
Start using the new version now?
|
||||
</p>
|
||||
</VStack>
|
||||
),
|
||||
action: ({ hide }) => (
|
||||
<ButtonInfiniteLoading
|
||||
size="xs"
|
||||
className="mr-auto min-w-[5rem]"
|
||||
color="primary"
|
||||
loadingChildren="Restarting..."
|
||||
onClick={() => {
|
||||
hide();
|
||||
setTimeout(() => invokeCmd("cmd_restart", {}), 200);
|
||||
}}
|
||||
>
|
||||
Relaunch Yaak
|
||||
</ButtonInfiniteLoading>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
async function showUpdateAvailableToast(updateInfo: UpdateInfo) {
|
||||
const UPDATE_TOAST_ID = "update-info";
|
||||
const { version, replyEventId, downloaded } = updateInfo;
|
||||
|
||||
jotaiStore.set(updateAvailableAtom, { version, downloaded });
|
||||
|
||||
// Acknowledge the event, so we don't time out and try the fallback update logic
|
||||
await emit<UpdateResponse>(replyEventId, { type: "ack" });
|
||||
|
||||
showToast({
|
||||
id: UPDATE_TOAST_ID,
|
||||
color: "info",
|
||||
timeout: null,
|
||||
message: (
|
||||
<VStack>
|
||||
<h2 className="font-semibold">Yaak {version} is available</h2>
|
||||
<p className="text-text-subtle text-sm">
|
||||
{downloaded ? "Do you want to install" : "Download and install"} the
|
||||
update?
|
||||
</p>
|
||||
</VStack>
|
||||
),
|
||||
action: () => (
|
||||
<HStack space={1.5}>
|
||||
<ButtonInfiniteLoading
|
||||
size="xs"
|
||||
color="info"
|
||||
className="min-w-[10rem]"
|
||||
loadingChildren={downloaded ? "Installing..." : "Downloading..."}
|
||||
onClick={async () => {
|
||||
await emit<UpdateResponse>(replyEventId, {
|
||||
type: "action",
|
||||
action: "install",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{downloaded ? "Install Now" : "Download and Install"}
|
||||
</ButtonInfiniteLoading>
|
||||
<Button
|
||||
size="xs"
|
||||
color="info"
|
||||
variant="border"
|
||||
rightSlot={<Icon icon="external_link" />}
|
||||
onClick={async () => {
|
||||
await openUrl(`https://yaak.app/changelog/${version}`);
|
||||
}}
|
||||
>
|
||||
What's New
|
||||
</Button>
|
||||
</HStack>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
function showPluginUpdatesToast(updateInfo: PluginUpdateNotification) {
|
||||
const PLUGIN_UPDATE_TOAST_ID = "plugin-updates";
|
||||
const count = updateInfo.updateCount;
|
||||
const pluginNames = updateInfo.plugins.map((p: { name: string }) => p.name);
|
||||
|
||||
showToast({
|
||||
id: PLUGIN_UPDATE_TOAST_ID,
|
||||
color: "info",
|
||||
timeout: null,
|
||||
message: (
|
||||
<VStack>
|
||||
<h2 className="font-semibold">
|
||||
{count === 1 ? "1 plugin update" : `${count} plugin updates`}{" "}
|
||||
available
|
||||
</h2>
|
||||
<p className="text-text-subtle text-sm">
|
||||
{count === 1
|
||||
? pluginNames[0]
|
||||
: `${pluginNames.slice(0, 2).join(", ")}${count > 2 ? `, and ${count - 2} more` : ""}`}
|
||||
</p>
|
||||
</VStack>
|
||||
),
|
||||
action: ({ hide }) => (
|
||||
<HStack space={1.5}>
|
||||
<ButtonInfiniteLoading
|
||||
size="xs"
|
||||
color="info"
|
||||
className="min-w-[5rem]"
|
||||
loadingChildren="Updating..."
|
||||
onClick={async () => {
|
||||
const updated = await updateAllPlugins();
|
||||
hide();
|
||||
if (updated.length > 0) {
|
||||
showToast({
|
||||
color: "success",
|
||||
message: `Successfully updated ${updated.length} plugin${updated.length === 1 ? "" : "s"}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
Update All
|
||||
</ButtonInfiniteLoading>
|
||||
<Button
|
||||
size="xs"
|
||||
color="info"
|
||||
variant="border"
|
||||
onClick={() => {
|
||||
hide();
|
||||
openSettings.mutate("plugins:installed");
|
||||
}}
|
||||
>
|
||||
View Updates
|
||||
</Button>
|
||||
</HStack>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
function showNotificationToast(n: YaakNotification) {
|
||||
const actionUrl = n.action?.url;
|
||||
const actionLabel = n.action?.label;
|
||||
showToast({
|
||||
id: n.id,
|
||||
timeout: n.timeout ?? null,
|
||||
color: stringToColor(n.color) ?? undefined,
|
||||
message: (
|
||||
<VStack>
|
||||
{n.title && <h2 className="font-semibold">{n.title}</h2>}
|
||||
<p className="text-text-subtle text-sm">{n.message}</p>
|
||||
</VStack>
|
||||
),
|
||||
onClose: () => {
|
||||
invokeCmd("cmd_dismiss_notification", { notificationId: n.id }).catch(
|
||||
console.error,
|
||||
);
|
||||
},
|
||||
action: ({ hide }) => {
|
||||
return actionLabel && actionUrl ? (
|
||||
<Button
|
||||
size="xs"
|
||||
color={stringToColor(n.color) ?? undefined}
|
||||
className="mr-auto min-w-[5rem]"
|
||||
rightSlot={<Icon icon="external_link" />}
|
||||
onClick={() => {
|
||||
hide();
|
||||
return openUrl(actionUrl);
|
||||
}}
|
||||
>
|
||||
{actionLabel}
|
||||
</Button>
|
||||
) : null;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export type { Appearance } from "@yaakapp-internal/theme";
|
||||
export {
|
||||
getCSSAppearance,
|
||||
getWindowAppearance,
|
||||
resolveAppearance,
|
||||
subscribeToPreferredAppearance,
|
||||
subscribeToWindowAppearanceChange,
|
||||
} from "@yaakapp-internal/theme";
|
||||
@@ -1,45 +0,0 @@
|
||||
import type { GetThemesResponse } from "@yaakapp-internal/plugins";
|
||||
import { defaultDarkTheme, defaultLightTheme } from "@yaakapp-internal/theme";
|
||||
import { invokeCmd } from "../tauri";
|
||||
import type { Appearance } from "./appearance";
|
||||
import { resolveAppearance } from "./appearance";
|
||||
|
||||
export { defaultDarkTheme, defaultLightTheme } from "@yaakapp-internal/theme";
|
||||
|
||||
export async function getThemes() {
|
||||
const themes = (
|
||||
await invokeCmd<GetThemesResponse[]>("cmd_get_themes")
|
||||
).flatMap((t) => t.themes);
|
||||
themes.sort((a, b) => a.label.localeCompare(b.label));
|
||||
// Remove duplicates, in case multiple plugins provide the same theme
|
||||
const uniqueThemes = Array.from(
|
||||
new Map(themes.map((t) => [t.id, t])).values(),
|
||||
);
|
||||
return { themes: [defaultDarkTheme, defaultLightTheme, ...uniqueThemes] };
|
||||
}
|
||||
|
||||
export async function getResolvedTheme(
|
||||
preferredAppearance: Appearance,
|
||||
appearanceSetting: string,
|
||||
themeLight: string,
|
||||
themeDark: string,
|
||||
) {
|
||||
const appearance = resolveAppearance(preferredAppearance, appearanceSetting);
|
||||
const { themes } = await getThemes();
|
||||
|
||||
const darkThemes = themes.filter((t) => t.dark);
|
||||
const lightThemes = themes.filter((t) => !t.dark);
|
||||
|
||||
const dark =
|
||||
darkThemes.find((t) => t.id === themeDark) ??
|
||||
darkThemes[0] ??
|
||||
defaultDarkTheme;
|
||||
const light =
|
||||
lightThemes.find((t) => t.id === themeLight) ??
|
||||
lightThemes[0] ??
|
||||
defaultLightTheme;
|
||||
|
||||
const active = appearance === "dark" ? dark : light;
|
||||
|
||||
return { dark, light, active };
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export type {
|
||||
YaakColorKey,
|
||||
YaakColors,
|
||||
YaakTheme,
|
||||
} from "@yaakapp-internal/theme";
|
||||
export {
|
||||
addThemeStylesToDocument,
|
||||
applyThemeToDocument,
|
||||
completeTheme,
|
||||
getThemeCSS,
|
||||
indent,
|
||||
setThemeOnDocument,
|
||||
} from "@yaakapp-internal/theme";
|
||||
@@ -1 +0,0 @@
|
||||
export { YaakColor } from "@yaakapp-internal/theme";
|
||||
@@ -1,47 +0,0 @@
|
||||
import "./main.css";
|
||||
import { RouterProvider } from "@tanstack/react-router";
|
||||
import { type } from "@tauri-apps/plugin-os";
|
||||
import {
|
||||
changeModelStoreWorkspace,
|
||||
initModelStore,
|
||||
} from "@yaakapp-internal/models";
|
||||
import { setPlatformOnDocument } from "@yaakapp-internal/theme";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import { initSync } from "./init/sync";
|
||||
import { initGlobalListeners } from "./lib/initGlobalListeners";
|
||||
import { jotaiStore } from "./lib/jotai";
|
||||
import { router } from "./lib/router";
|
||||
|
||||
const osType = type();
|
||||
setPlatformOnDocument(osType);
|
||||
|
||||
window.addEventListener("keydown", (e) => {
|
||||
const rx = /input|select|textarea/i;
|
||||
|
||||
const target = e.target;
|
||||
if (e.key !== "Backspace") return;
|
||||
if (!(target instanceof Element)) return;
|
||||
if (target.getAttribute("contenteditable") !== null) return;
|
||||
|
||||
if (
|
||||
!rx.test(target.tagName) ||
|
||||
("disabled" in target && target.disabled) ||
|
||||
("readOnly" in target && target.readOnly)
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize a bunch of watchers
|
||||
initSync();
|
||||
initModelStore(jotaiStore);
|
||||
initGlobalListeners();
|
||||
await changeModelStoreWorkspace(null); // Load global models
|
||||
|
||||
console.log("Creating React root");
|
||||
createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<StrictMode>
|
||||
<RouterProvider router={router} />
|
||||
</StrictMode>,
|
||||
);
|
||||
@@ -1,16 +0,0 @@
|
||||
const sharedConfig = require("@yaakapp-internal/tailwind-config");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
...sharedConfig,
|
||||
content: [
|
||||
"./*.{html,ts,tsx}",
|
||||
"./commands/**/*.{ts,tsx}",
|
||||
"./components/**/*.{ts,tsx}",
|
||||
"./hooks/**/*.{ts,tsx}",
|
||||
"./init/**/*.{ts,tsx}",
|
||||
"./lib/**/*.{ts,tsx}",
|
||||
"./routes/**/*.{ts,tsx}",
|
||||
"../../packages/ui/src/**/*.{ts,tsx}",
|
||||
],
|
||||
};
|
||||
@@ -1,67 +0,0 @@
|
||||
// @ts-ignore
|
||||
import { tanstackRouter } from "@tanstack/router-plugin/vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { createRequire } from "node:module";
|
||||
import path from "node:path";
|
||||
import { defineConfig, normalizePath } from "vite";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
import topLevelAwait from "vite-plugin-top-level-await";
|
||||
import wasm from "vite-plugin-wasm";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const cMapsDir = normalizePath(
|
||||
path.join(path.dirname(require.resolve("pdfjs-dist/package.json")), "cmaps"),
|
||||
);
|
||||
const standardFontsDir = normalizePath(
|
||||
path.join(
|
||||
path.dirname(require.resolve("pdfjs-dist/package.json")),
|
||||
"standard_fonts",
|
||||
),
|
||||
);
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => {
|
||||
return {
|
||||
plugins: [
|
||||
wasm(),
|
||||
tanstackRouter({
|
||||
target: "react",
|
||||
routesDirectory: "./routes",
|
||||
generatedRouteTree: "./routeTree.gen.ts",
|
||||
autoCodeSplitting: true,
|
||||
}),
|
||||
svgr(),
|
||||
react(),
|
||||
topLevelAwait(),
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{ src: cMapsDir, dest: "" },
|
||||
{ src: standardFontsDir, dest: "" },
|
||||
],
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
sourcemap: true,
|
||||
outDir: "../../dist/apps/yaak-client",
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
// Make chunk names readable
|
||||
chunkFileNames: "assets/chunk-[name]-[hash].js",
|
||||
entryFileNames: "assets/entry-[name]-[hash].js",
|
||||
assetFileNames: "assets/asset-[name]-[hash][extname]",
|
||||
},
|
||||
},
|
||||
},
|
||||
clearScreen: false,
|
||||
server: {
|
||||
port: parseInt(
|
||||
process.env.YAAK_CLIENT_DEV_PORT ?? process.env.YAAK_DEV_PORT ?? "1420",
|
||||
10,
|
||||
),
|
||||
strictPort: true,
|
||||
},
|
||||
envPrefix: ["VITE_", "TAURI_"],
|
||||
};
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Yaak Proxy</title>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html,
|
||||
body {
|
||||
background-color: #1b1a29;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-base">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/theme.ts"></script>
|
||||
<script type="module" src="/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,92 +0,0 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
@apply w-full h-full overflow-hidden text-text bg-surface;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font-family-interface: "";
|
||||
--font-family-editor: "";
|
||||
}
|
||||
|
||||
:root {
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
|
||||
html[data-platform="linux"] {
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
::selection {
|
||||
@apply bg-selection;
|
||||
}
|
||||
|
||||
:not(a),
|
||||
:not(input):not(textarea),
|
||||
:not(input):not(textarea)::after,
|
||||
:not(input):not(textarea)::before {
|
||||
@apply select-none cursor-default;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
&::placeholder {
|
||||
@apply text-placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
a,
|
||||
a[href] * {
|
||||
@apply cursor-pointer !important;
|
||||
}
|
||||
|
||||
table th {
|
||||
@apply text-left;
|
||||
}
|
||||
|
||||
:not(iframe) {
|
||||
&::-webkit-scrollbar,
|
||||
&::-webkit-scrollbar-corner {
|
||||
@apply w-[8px] h-[8px] bg-transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
@apply bg-transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
@apply bg-text-subtlest rounded-[4px] opacity-20;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
@apply opacity-40 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-scrollbars {
|
||||
&::-webkit-scrollbar-corner,
|
||||
&::-webkit-scrollbar {
|
||||
@apply hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
--transition-duration: 100ms ease-in-out;
|
||||
--color-white: 255 100% 100%;
|
||||
--color-black: 255 0% 0%;
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
import "./main.css";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { type } from "@tauri-apps/plugin-os";
|
||||
import { Button, HeaderSize } from "@yaakapp-internal/ui";
|
||||
import classNames from "classnames";
|
||||
import { StrictMode } from "react";
|
||||
import { useState } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
type ProxyStartResult = {
|
||||
port: number;
|
||||
alreadyRunning: boolean;
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [status, setStatus] = useState("Idle");
|
||||
const [port, setPort] = useState<number | null>(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const osType = type();
|
||||
|
||||
async function startProxy() {
|
||||
setBusy(true);
|
||||
setStatus("Starting...");
|
||||
try {
|
||||
const result = await invoke<ProxyStartResult>("proxy_start", {
|
||||
port: 9090,
|
||||
});
|
||||
setPort(result.port);
|
||||
setStatus(result.alreadyRunning ? "Already running" : "Running");
|
||||
} catch (err) {
|
||||
setStatus(`Failed: ${String(err)}`);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopProxy() {
|
||||
setBusy(true);
|
||||
setStatus("Stopping...");
|
||||
try {
|
||||
const stopped = await invoke<boolean>("proxy_stop");
|
||||
setPort(null);
|
||||
setStatus(stopped ? "Stopped" : "Not running");
|
||||
} catch (err) {
|
||||
setStatus(`Failed: ${String(err)}`);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames('h-full w-full grid grid-rows-[auto_1fr]', osType === 'linux' && 'border border-border-subtle')}>
|
||||
<HeaderSize
|
||||
size="lg"
|
||||
osType={osType}
|
||||
hideWindowControls={false}
|
||||
useNativeTitlebar={false}
|
||||
interfaceScale={1}
|
||||
className="x-theme-appHeader bg-surface"
|
||||
>
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className="flex items-center h-full px-2 text-sm font-semibold text-text-subtle"
|
||||
>
|
||||
Yaak Proxy
|
||||
</div>
|
||||
</HeaderSize>
|
||||
<main className="overflow-auto p-6">
|
||||
<section className="flex items-start">
|
||||
<div className="flex w-full max-w-xl flex-col gap-4">
|
||||
<div>
|
||||
<p className="text-sm text-text-subtle">Status: {status}</p>
|
||||
<p className="mt-1 text-sm text-text-subtle">
|
||||
Port: {port ?? "Not running"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<Button
|
||||
disabled={busy}
|
||||
onClick={startProxy}
|
||||
size="sm"
|
||||
tone="primary"
|
||||
>
|
||||
Start Proxy
|
||||
</Button>
|
||||
<Button
|
||||
disabled={busy}
|
||||
onClick={stopProxy}
|
||||
size="sm"
|
||||
variant="border"
|
||||
>
|
||||
Stop Proxy
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<App />
|
||||
</QueryClientProvider>
|
||||
</StrictMode>,
|
||||
);
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "@yaakapp/yaak-proxy",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev --force",
|
||||
"build": "vite build",
|
||||
"lint": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "^5.90.5",
|
||||
"@tauri-apps/api": "^2.9.1",
|
||||
"@tauri-apps/plugin-os": "^2.3.2",
|
||||
"@yaakapp-internal/theme": "^1.0.0",
|
||||
"@yaakapp-internal/ui": "^1.0.0",
|
||||
"classnames": "^2.5.1",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.1.8",
|
||||
"@types/react-dom": "^19.1.6",
|
||||
"@vitejs/plugin-react": "^4.6.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^7.0.8"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
require("@tailwindcss/nesting")(require("postcss-nesting")),
|
||||
require("tailwindcss"),
|
||||
require("autoprefixer"),
|
||||
],
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
const sharedConfig = require("@yaakapp-internal/tailwind-config");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
...sharedConfig,
|
||||
content: ["./*.{html,ts,tsx}", "../../packages/ui/src/**/*.{ts,tsx}"],
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
import {
|
||||
applyThemeToDocument,
|
||||
defaultDarkTheme,
|
||||
platformFromUserAgent,
|
||||
setPlatformOnDocument,
|
||||
} from "@yaakapp-internal/theme";
|
||||
|
||||
setPlatformOnDocument(platformFromUserAgent(navigator.userAgent));
|
||||
applyThemeToDocument(defaultDarkTheme);
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2021",
|
||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||
"useDefineForClassFields": true,
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"paths": {
|
||||
"@yaakapp-internal/theme": ["../../packages/theme/src/index.ts"],
|
||||
"@yaakapp-internal/theme/*": ["../../packages/theme/src/*"],
|
||||
"@yaakapp-internal/ui": ["../../packages/ui/src/index.ts"],
|
||||
"@yaakapp-internal/ui/*": ["../../packages/ui/src/*"],
|
||||
},
|
||||
},
|
||||
"include": ["."],
|
||||
"exclude": ["vite.config.ts"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }],
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noUncheckedIndexedAccess": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
1
apps/yaak-proxy/vite-env.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
@@ -1,16 +0,0 @@
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
build: {
|
||||
outDir: "../../dist/apps/yaak-proxy",
|
||||
emptyOutDir: true,
|
||||
},
|
||||
clearScreen: false,
|
||||
server: {
|
||||
port: parseInt(process.env.YAAK_PROXY_DEV_PORT ?? "2420", 10),
|
||||
strictPort: true,
|
||||
},
|
||||
envPrefix: ["VITE_", "TAURI_"],
|
||||
});
|
||||
@@ -42,10 +42,10 @@
|
||||
"!scripts",
|
||||
"!crates",
|
||||
"!crates-tauri",
|
||||
"!apps/yaak-client/tailwind.config.cjs",
|
||||
"!apps/yaak-client/postcss.config.cjs",
|
||||
"!apps/yaak-client/vite.config.ts",
|
||||
"!apps/yaak-client/routeTree.gen.ts",
|
||||
"!src-web/tailwind.config.cjs",
|
||||
"!src-web/postcss.config.cjs",
|
||||
"!src-web/vite.config.ts",
|
||||
"!src-web/routeTree.gen.ts",
|
||||
"!packages/plugin-runtime-types/lib",
|
||||
"!**/bindings",
|
||||
"!flatpak"
|
||||
|
||||
@@ -13,10 +13,10 @@ use yaak_plugins::manager::PluginManager;
|
||||
|
||||
const EMBEDDED_PLUGIN_RUNTIME: &str = include_str!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/../../crates-tauri/yaak-app-client/vendored/plugin-runtime/index.cjs"
|
||||
"/../../crates-tauri/yaak-app/vendored/plugin-runtime/index.cjs"
|
||||
));
|
||||
static EMBEDDED_VENDORED_PLUGINS: Dir<'_> =
|
||||
include_dir!("$CARGO_MANIFEST_DIR/../../crates-tauri/yaak-app-client/vendored/plugins");
|
||||
include_dir!("$CARGO_MANIFEST_DIR/../../crates-tauri/yaak-app/vendored/plugins");
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct CliExecutionContext {
|
||||
@@ -36,71 +36,72 @@ pub struct CliContext {
|
||||
}
|
||||
|
||||
impl CliContext {
|
||||
pub fn new(data_dir: PathBuf, app_id: &str) -> Self {
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, blob_manager, _rx) =
|
||||
match yaak_models::init_standalone(&db_path, &blob_path) {
|
||||
Ok(v) => v,
|
||||
pub async fn new(
|
||||
data_dir: PathBuf,
|
||||
query_manager: QueryManager,
|
||||
blob_manager: BlobManager,
|
||||
encryption_manager: Arc<EncryptionManager>,
|
||||
with_plugins: bool,
|
||||
execution_context: CliExecutionContext,
|
||||
) -> Self {
|
||||
let plugin_manager = if with_plugins {
|
||||
let vendored_plugin_dir = data_dir.join("vendored-plugins");
|
||||
let installed_plugin_dir = data_dir.join("installed-plugins");
|
||||
let node_bin_path = PathBuf::from("node");
|
||||
|
||||
prepare_embedded_vendored_plugins(&vendored_plugin_dir)
|
||||
.expect("Failed to prepare bundled plugins");
|
||||
|
||||
let plugin_runtime_main =
|
||||
std::env::var("YAAK_PLUGIN_RUNTIME").map(PathBuf::from).unwrap_or_else(|_| {
|
||||
prepare_embedded_plugin_runtime(&data_dir)
|
||||
.expect("Failed to prepare embedded plugin runtime")
|
||||
});
|
||||
|
||||
match PluginManager::new(
|
||||
vendored_plugin_dir,
|
||||
installed_plugin_dir,
|
||||
node_bin_path,
|
||||
plugin_runtime_main,
|
||||
&query_manager,
|
||||
&PluginContext::new_empty(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(plugin_manager) => Some(Arc::new(plugin_manager)),
|
||||
Err(err) => {
|
||||
eprintln!("Error: Failed to initialize database: {err}");
|
||||
std::process::exit(1);
|
||||
eprintln!("Warning: Failed to initialize plugins: {err}");
|
||||
None
|
||||
}
|
||||
};
|
||||
let encryption_manager = Arc::new(EncryptionManager::new(query_manager.clone(), app_id));
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let plugin_event_bridge = if let Some(plugin_manager) = &plugin_manager {
|
||||
Some(
|
||||
CliPluginEventBridge::start(
|
||||
plugin_manager.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager.clone(),
|
||||
encryption_manager.clone(),
|
||||
data_dir.clone(),
|
||||
execution_context.clone(),
|
||||
)
|
||||
.await,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
data_dir,
|
||||
query_manager,
|
||||
blob_manager,
|
||||
encryption_manager,
|
||||
plugin_manager: None,
|
||||
plugin_event_bridge: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init_plugins(&mut self, execution_context: CliExecutionContext) {
|
||||
let vendored_plugin_dir = self.data_dir.join("vendored-plugins");
|
||||
let installed_plugin_dir = self.data_dir.join("installed-plugins");
|
||||
let node_bin_path = PathBuf::from("node");
|
||||
|
||||
prepare_embedded_vendored_plugins(&vendored_plugin_dir)
|
||||
.expect("Failed to prepare bundled plugins");
|
||||
|
||||
let plugin_runtime_main =
|
||||
std::env::var("YAAK_PLUGIN_RUNTIME").map(PathBuf::from).unwrap_or_else(|_| {
|
||||
prepare_embedded_plugin_runtime(&self.data_dir)
|
||||
.expect("Failed to prepare embedded plugin runtime")
|
||||
});
|
||||
|
||||
match PluginManager::new(
|
||||
vendored_plugin_dir,
|
||||
installed_plugin_dir,
|
||||
node_bin_path,
|
||||
plugin_runtime_main,
|
||||
&self.query_manager,
|
||||
&PluginContext::new_empty(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(plugin_manager) => {
|
||||
let plugin_manager = Arc::new(plugin_manager);
|
||||
let plugin_event_bridge = CliPluginEventBridge::start(
|
||||
plugin_manager.clone(),
|
||||
self.query_manager.clone(),
|
||||
self.blob_manager.clone(),
|
||||
self.encryption_manager.clone(),
|
||||
self.data_dir.clone(),
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
self.plugin_manager = Some(plugin_manager);
|
||||
*self.plugin_event_bridge.lock().await = Some(plugin_event_bridge);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("Warning: Failed to initialize plugins: {err}");
|
||||
}
|
||||
plugin_manager,
|
||||
plugin_event_bridge: Mutex::new(plugin_event_bridge),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,10 @@ mod version_check;
|
||||
use clap::Parser;
|
||||
use cli::{Cli, Commands, PluginCommands, RequestCommands};
|
||||
use context::{CliContext, CliExecutionContext};
|
||||
use std::sync::Arc;
|
||||
use yaak_crypto::manager::EncryptionManager;
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::query_manager::QueryManager;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
@@ -36,6 +39,17 @@ async fn main() {
|
||||
|
||||
version_check::maybe_check_for_updates().await;
|
||||
|
||||
let db_path = data_dir.join("db.sqlite");
|
||||
let blob_path = data_dir.join("blobs.sqlite");
|
||||
let (query_manager, blob_manager, _rx) =
|
||||
match yaak_models::init_standalone(&db_path, &blob_path) {
|
||||
Ok(v) => v,
|
||||
Err(err) => {
|
||||
eprintln!("Error: Failed to initialize database: {err}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let exit_code = match command {
|
||||
Commands::Auth(args) => commands::auth::run(args).await,
|
||||
Commands::Plugin(args) => match args.command {
|
||||
@@ -44,8 +58,18 @@ async fn main() {
|
||||
PluginCommands::Generate(args) => commands::plugin::run_generate(args).await,
|
||||
PluginCommands::Publish(args) => commands::plugin::run_publish(args).await,
|
||||
PluginCommands::Install(install_args) => {
|
||||
let mut context = CliContext::new(data_dir.clone(), app_id);
|
||||
context.init_plugins(CliExecutionContext::default()).await;
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
let execution_context = CliExecutionContext::default();
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
true,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
let exit_code = commands::plugin::run_install(&context, install_args).await;
|
||||
context.shutdown().await;
|
||||
exit_code
|
||||
@@ -56,15 +80,27 @@ async fn main() {
|
||||
Commands::Generate(args) => commands::plugin::run_generate(args).await,
|
||||
Commands::Publish(args) => commands::plugin::run_publish(args).await,
|
||||
Commands::Send(args) => {
|
||||
let mut context = CliContext::new(data_dir.clone(), app_id);
|
||||
match resolve_send_execution_context(
|
||||
&context,
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
|
||||
let execution_context_result = resolve_send_execution_context(
|
||||
&query_manager,
|
||||
&args.id,
|
||||
environment.as_deref(),
|
||||
cookie_jar.as_deref(),
|
||||
) {
|
||||
);
|
||||
match execution_context_result {
|
||||
Ok(execution_context) => {
|
||||
context.init_plugins(execution_context).await;
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
true,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
|
||||
let exit_code = commands::send::run(
|
||||
&context,
|
||||
args,
|
||||
@@ -83,22 +119,48 @@ async fn main() {
|
||||
}
|
||||
}
|
||||
Commands::CookieJar(args) => {
|
||||
let context = CliContext::new(data_dir.clone(), app_id);
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
let execution_context = CliExecutionContext::default();
|
||||
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
false,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
let exit_code = commands::cookie_jar::run(&context, args);
|
||||
context.shutdown().await;
|
||||
exit_code
|
||||
}
|
||||
Commands::Workspace(args) => {
|
||||
let context = CliContext::new(data_dir.clone(), app_id);
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
let execution_context = CliExecutionContext::default();
|
||||
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
false,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
let exit_code = commands::workspace::run(&context, args);
|
||||
context.shutdown().await;
|
||||
exit_code
|
||||
}
|
||||
Commands::Request(args) => {
|
||||
let mut context = CliContext::new(data_dir.clone(), app_id);
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
|
||||
let execution_context_result = match &args.command {
|
||||
RequestCommands::Send { request_id } => resolve_request_execution_context(
|
||||
&context,
|
||||
&query_manager,
|
||||
request_id,
|
||||
environment.as_deref(),
|
||||
cookie_jar.as_deref(),
|
||||
@@ -111,9 +173,16 @@ async fn main() {
|
||||
&args.command,
|
||||
RequestCommands::Send { .. } | RequestCommands::Schema { .. }
|
||||
);
|
||||
if with_plugins {
|
||||
context.init_plugins(execution_context).await;
|
||||
}
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
with_plugins,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
|
||||
let exit_code = commands::request::run(
|
||||
&context,
|
||||
args,
|
||||
@@ -132,13 +201,37 @@ async fn main() {
|
||||
}
|
||||
}
|
||||
Commands::Folder(args) => {
|
||||
let context = CliContext::new(data_dir.clone(), app_id);
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
let execution_context = CliExecutionContext::default();
|
||||
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
false,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
let exit_code = commands::folder::run(&context, args);
|
||||
context.shutdown().await;
|
||||
exit_code
|
||||
}
|
||||
Commands::Environment(args) => {
|
||||
let context = CliContext::new(data_dir.clone(), app_id);
|
||||
let query_manager = query_manager.clone();
|
||||
let blob_manager = blob_manager.clone();
|
||||
let execution_context = CliExecutionContext::default();
|
||||
|
||||
let context = CliContext::new(
|
||||
data_dir.clone(),
|
||||
query_manager.clone(),
|
||||
blob_manager,
|
||||
Arc::new(EncryptionManager::new(query_manager, app_id)),
|
||||
false,
|
||||
execution_context,
|
||||
)
|
||||
.await;
|
||||
let exit_code = commands::environment::run(&context, args);
|
||||
context.shutdown().await;
|
||||
exit_code
|
||||
@@ -151,18 +244,19 @@ async fn main() {
|
||||
}
|
||||
|
||||
fn resolve_send_execution_context(
|
||||
context: &CliContext,
|
||||
query_manager: &QueryManager,
|
||||
id: &str,
|
||||
environment: Option<&str>,
|
||||
explicit_cookie_jar_id: Option<&str>,
|
||||
) -> Result<CliExecutionContext, String> {
|
||||
if let Ok(request) = context.db().get_any_request(id) {
|
||||
if let Ok(request) = query_manager.connect().get_any_request(id) {
|
||||
let (request_id, workspace_id) = match request {
|
||||
AnyRequest::HttpRequest(r) => (Some(r.id), r.workspace_id),
|
||||
AnyRequest::GrpcRequest(r) => (Some(r.id), r.workspace_id),
|
||||
AnyRequest::WebsocketRequest(r) => (Some(r.id), r.workspace_id),
|
||||
};
|
||||
let cookie_jar_id = resolve_cookie_jar_id(context, &workspace_id, explicit_cookie_jar_id)?;
|
||||
let cookie_jar_id =
|
||||
resolve_cookie_jar_id(query_manager, &workspace_id, explicit_cookie_jar_id)?;
|
||||
return Ok(CliExecutionContext {
|
||||
request_id,
|
||||
workspace_id: Some(workspace_id),
|
||||
@@ -171,9 +265,9 @@ fn resolve_send_execution_context(
|
||||
});
|
||||
}
|
||||
|
||||
if let Ok(folder) = context.db().get_folder(id) {
|
||||
if let Ok(folder) = query_manager.connect().get_folder(id) {
|
||||
let cookie_jar_id =
|
||||
resolve_cookie_jar_id(context, &folder.workspace_id, explicit_cookie_jar_id)?;
|
||||
resolve_cookie_jar_id(query_manager, &folder.workspace_id, explicit_cookie_jar_id)?;
|
||||
return Ok(CliExecutionContext {
|
||||
request_id: None,
|
||||
workspace_id: Some(folder.workspace_id),
|
||||
@@ -182,8 +276,9 @@ fn resolve_send_execution_context(
|
||||
});
|
||||
}
|
||||
|
||||
if let Ok(workspace) = context.db().get_workspace(id) {
|
||||
let cookie_jar_id = resolve_cookie_jar_id(context, &workspace.id, explicit_cookie_jar_id)?;
|
||||
if let Ok(workspace) = query_manager.connect().get_workspace(id) {
|
||||
let cookie_jar_id =
|
||||
resolve_cookie_jar_id(query_manager, &workspace.id, explicit_cookie_jar_id)?;
|
||||
return Ok(CliExecutionContext {
|
||||
request_id: None,
|
||||
workspace_id: Some(workspace.id),
|
||||
@@ -196,13 +291,13 @@ fn resolve_send_execution_context(
|
||||
}
|
||||
|
||||
fn resolve_request_execution_context(
|
||||
context: &CliContext,
|
||||
query_manager: &QueryManager,
|
||||
request_id: &str,
|
||||
environment: Option<&str>,
|
||||
explicit_cookie_jar_id: Option<&str>,
|
||||
) -> Result<CliExecutionContext, String> {
|
||||
let request = context
|
||||
.db()
|
||||
let request = query_manager
|
||||
.connect()
|
||||
.get_any_request(request_id)
|
||||
.map_err(|e| format!("Failed to get request: {e}"))?;
|
||||
|
||||
@@ -211,7 +306,8 @@ fn resolve_request_execution_context(
|
||||
AnyRequest::GrpcRequest(r) => r.workspace_id,
|
||||
AnyRequest::WebsocketRequest(r) => r.workspace_id,
|
||||
};
|
||||
let cookie_jar_id = resolve_cookie_jar_id(context, &workspace_id, explicit_cookie_jar_id)?;
|
||||
let cookie_jar_id =
|
||||
resolve_cookie_jar_id(query_manager, &workspace_id, explicit_cookie_jar_id)?;
|
||||
|
||||
Ok(CliExecutionContext {
|
||||
request_id: Some(request_id.to_string()),
|
||||
@@ -222,7 +318,7 @@ fn resolve_request_execution_context(
|
||||
}
|
||||
|
||||
fn resolve_cookie_jar_id(
|
||||
context: &CliContext,
|
||||
query_manager: &QueryManager,
|
||||
workspace_id: &str,
|
||||
explicit_cookie_jar_id: Option<&str>,
|
||||
) -> Result<Option<String>, String> {
|
||||
@@ -230,8 +326,8 @@ fn resolve_cookie_jar_id(
|
||||
return Ok(Some(cookie_jar_id.to_string()));
|
||||
}
|
||||
|
||||
let default_cookie_jar = context
|
||||
.db()
|
||||
let default_cookie_jar = query_manager
|
||||
.connect()
|
||||
.list_cookie_jars(workspace_id)
|
||||
.map_err(|e| format!("Failed to list cookie jars: {e}"))?
|
||||
.into_iter()
|
||||
|
||||
@@ -16,7 +16,6 @@ use yaak::send::{SendHttpRequestWithPluginsParams, send_http_request_with_plugin
|
||||
use yaak_crypto::manager::EncryptionManager;
|
||||
use yaak_models::blob_manager::BlobManager;
|
||||
use yaak_models::models::{Environment, GrpcRequest, HttpRequestHeader};
|
||||
use yaak_models::queries::any_request::AnyRequest;
|
||||
use yaak_models::query_manager::QueryManager;
|
||||
use yaak_models::render::make_vars_hashmap;
|
||||
use yaak_models::util::UpdateSource;
|
||||
@@ -362,19 +361,10 @@ async fn build_plugin_reply(
|
||||
..event.context.clone()
|
||||
};
|
||||
|
||||
let folder_id = execution_context.request_id.as_ref().and_then(|rid| {
|
||||
match host_context.query_manager.connect().get_any_request(rid) {
|
||||
Ok(AnyRequest::HttpRequest(r)) => r.folder_id,
|
||||
Ok(AnyRequest::GrpcRequest(r)) => r.folder_id,
|
||||
Ok(AnyRequest::WebsocketRequest(r)) => r.folder_id,
|
||||
Err(_) => None,
|
||||
}
|
||||
});
|
||||
|
||||
let environment_chain =
|
||||
match host_context.query_manager.connect().resolve_environments(
|
||||
&workspace_id,
|
||||
folder_id.as_deref(),
|
||||
None,
|
||||
execution_context.environment_id.as_deref(),
|
||||
) {
|
||||
Ok(chain) => chain,
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "@yaakapp-internal/tauri-client",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "bindings/index.ts"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
tauri_app_client_lib::run();
|
||||
}
|
||||
8
crates-tauri/yaak-app-proxy/.gitignore
vendored
@@ -1,8 +0,0 @@
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
target/
|
||||
|
||||
gen/*
|
||||
|
||||
**/permissions/autogenerated
|
||||
**/permissions/schemas
|
||||
@@ -1,21 +0,0 @@
|
||||
[package]
|
||||
name = "yaak-app-proxy"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
authors = ["Gregory Schier"]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "tauri_app_proxy_lib"
|
||||
crate-type = ["staticlib", "cdylib", "lib"]
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2.5.3", features = [] }
|
||||
|
||||
[dependencies]
|
||||
log = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
tauri = { workspace = true }
|
||||
tauri-plugin-os = "2.3.2"
|
||||
yaak-proxy = { workspace = true }
|
||||
yaak-window = { workspace = true }
|
||||
1
crates-tauri/yaak-app-proxy/bindings/index.ts
generated
@@ -1 +0,0 @@
|
||||
export {};
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"identifier": "default",
|
||||
"description": "Default capabilities for the Yaak Proxy app",
|
||||
"windows": [
|
||||
"*"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
"os:allow-os-type",
|
||||
"core:window:allow-close",
|
||||
"core:window:allow-is-fullscreen",
|
||||
"core:window:allow-is-maximized",
|
||||
"core:window:allow-maximize",
|
||||
"core:window:allow-minimize",
|
||||
"core:window:allow-start-dragging",
|
||||
"core:window:allow-unmaximize"
|
||||
]
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
use log::error;
|
||||
use serde::Serialize;
|
||||
use std::sync::Mutex;
|
||||
use tauri::{RunEvent, State};
|
||||
use yaak_proxy::ProxyHandle;
|
||||
use yaak_window::window::CreateWindowConfig;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProxyMetadata {
|
||||
name: String,
|
||||
version: String,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ProxyState {
|
||||
handle: Mutex<Option<ProxyHandle>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ProxyStartResult {
|
||||
port: u16,
|
||||
already_running: bool,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn proxy_metadata(app_handle: tauri::AppHandle) -> ProxyMetadata {
|
||||
ProxyMetadata {
|
||||
name: app_handle.package_info().name.clone(),
|
||||
version: app_handle.package_info().version.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn proxy_start(
|
||||
state: State<'_, ProxyState>,
|
||||
port: Option<u16>,
|
||||
) -> Result<ProxyStartResult, String> {
|
||||
let mut handle = state.handle.lock().map_err(|_| "failed to lock proxy state".to_string())?;
|
||||
|
||||
if let Some(existing) = handle.as_ref() {
|
||||
return Ok(ProxyStartResult { port: existing.port, already_running: true });
|
||||
}
|
||||
|
||||
let proxy_handle = yaak_proxy::start_proxy(port.unwrap_or(0))?;
|
||||
let started_port = proxy_handle.port;
|
||||
*handle = Some(proxy_handle);
|
||||
|
||||
Ok(ProxyStartResult { port: started_port, already_running: false })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn proxy_stop(state: State<'_, ProxyState>) -> Result<bool, String> {
|
||||
let mut handle = state.handle.lock().map_err(|_| "failed to lock proxy state".to_string())?;
|
||||
Ok(handle.take().is_some())
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.manage(ProxyState::default())
|
||||
.invoke_handler(tauri::generate_handler![proxy_metadata, proxy_start, proxy_stop])
|
||||
.build(tauri::generate_context!())
|
||||
.expect("error while building yaak proxy tauri application")
|
||||
.run(|app_handle, event| {
|
||||
if let RunEvent::Ready = event {
|
||||
let config = CreateWindowConfig {
|
||||
url: "/",
|
||||
label: "main",
|
||||
title: "Yaak Proxy",
|
||||
inner_size: Some((1000.0, 700.0)),
|
||||
visible: true,
|
||||
hide_titlebar: true,
|
||||
..Default::default()
|
||||
};
|
||||
if let Err(e) = yaak_window::window::create_window(app_handle, config) {
|
||||
error!("Failed to create proxy window: {e:?}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"productName": "Yaak Proxy",
|
||||
"version": "0.0.0",
|
||||
"identifier": "app.yaak.proxy",
|
||||
"build": {
|
||||
"beforeBuildCommand": "npm --prefix ../.. run proxy:tauri-before-build",
|
||||
"beforeDevCommand": "npm --prefix ../.. run proxy:tauri-before-dev",
|
||||
"devUrl": "http://localhost:2420",
|
||||
"frontendDist": "../../dist/apps/yaak-proxy"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": false,
|
||||
"windows": []
|
||||
},
|
||||
"bundle": {
|
||||
"icon": [
|
||||
"../yaak-app-client/icons/release/32x32.png",
|
||||
"../yaak-app-client/icons/release/128x128.png",
|
||||
"../yaak-app-client/icons/release/128x128@2x.png",
|
||||
"../yaak-app-client/icons/release/icon.icns",
|
||||
"../yaak-app-client/icons/release/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"productName": "Yaak Proxy Dev",
|
||||
"identifier": "app.yaak.proxy.dev",
|
||||
"bundle": {
|
||||
"icon": [
|
||||
"../yaak-app-client/icons/dev/32x32.png",
|
||||
"../yaak-app-client/icons/dev/128x128.png",
|
||||
"../yaak-app-client/icons/dev/128x128@2x.png",
|
||||
"../yaak-app-client/icons/dev/icon.icns",
|
||||
"../yaak-app-client/icons/dev/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"features": []
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Categories={{categories}}
|
||||
Comment={{comment}}
|
||||
Exec={{exec}}
|
||||
Icon={{icon}}
|
||||
Name={{name}}
|
||||
StartupWMClass={{exec}}
|
||||
Terminal=false
|
||||
Type=Application
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "yaak-app-client"
|
||||
name = "yaak-app"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
authors = ["Gregory Schier"]
|
||||
@@ -7,7 +7,7 @@ publish = false
|
||||
|
||||
# Produce a library for mobile support
|
||||
[lib]
|
||||
name = "tauri_app_client_lib"
|
||||
name = "tauri_app_lib"
|
||||
crate-type = ["staticlib", "cdylib", "lib"]
|
||||
|
||||
[features]
|
||||
@@ -75,5 +75,4 @@ yaak-sse = { workspace = true }
|
||||
yaak-sync = { workspace = true }
|
||||
yaak-templates = { workspace = true }
|
||||
yaak-tls = { workspace = true }
|
||||
yaak-window = { workspace = true }
|
||||
yaak-ws = { workspace = true }
|
||||
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 848 B |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |