diff --git a/apps/windows-client/package-lock.json b/apps/windows-client/package-lock.json index 4dd12ae..73cf8ca 100644 --- a/apps/windows-client/package-lock.json +++ b/apps/windows-client/package-lock.json @@ -9,6 +9,8 @@ "version": "0.1.0", "dependencies": { "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.1", + "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, @@ -1433,6 +1435,15 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.7.1.tgz", + "integrity": "sha512-OK1UBXYt+ojcmxMktzzuyonYIFta8CmAASpX+CA+DTGK24KlHjhYI6x2iOJ/TjZF4N7/ACK1oFmEOjIY9IhzOQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1771,6 +1782,15 @@ "yallist": "^3.0.2" } }, + "node_modules/lucide-react": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.23.0.tgz", + "integrity": "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/apps/windows-client/package.json b/apps/windows-client/package.json index 061beac..62c35bc 100644 --- a/apps/windows-client/package.json +++ b/apps/windows-client/package.json @@ -12,6 +12,8 @@ }, "dependencies": { "@tauri-apps/api": "^2.0.0", + "@tauri-apps/plugin-dialog": "^2.7.1", + "lucide-react": "^1.23.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, @@ -24,4 +26,3 @@ "vite": "^7.0.0" } } - diff --git a/apps/windows-client/src-tauri/Cargo.lock b/apps/windows-client/src-tauri/Cargo.lock index 2c14ca7..ce4a889 100644 --- a/apps/windows-client/src-tauri/Cargo.lock +++ b/apps/windows-client/src-tauri/Cargo.lock @@ -1932,6 +1932,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ "bitflags 2.13.0", "block2", + "libc", "objc2", "objc2-core-foundation", ] @@ -2396,6 +2397,30 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -3040,6 +3065,64 @@ dependencies = [ "tauri-utils", ] +[[package]] +name = "tauri-plugin" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.18", + "toml 1.1.2+spec-1.1.0", + "url", +] + [[package]] name = "tauri-runtime" version = "2.11.3" @@ -3618,6 +3701,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-dialog", ] [[package]] @@ -4047,6 +4131,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -4080,13 +4173,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows-threading" version = "0.1.0" @@ -4117,6 +4227,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -4129,6 +4245,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -4141,12 +4263,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -4159,6 +4293,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -4171,6 +4311,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -4183,6 +4329,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -4195,6 +4347,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" version = "0.5.40" diff --git a/apps/windows-client/src-tauri/Cargo.toml b/apps/windows-client/src-tauri/Cargo.toml index 22e8211..42c840e 100644 --- a/apps/windows-client/src-tauri/Cargo.toml +++ b/apps/windows-client/src-tauri/Cargo.toml @@ -16,4 +16,5 @@ tauri-build = { version = "2", features = [] } tauri = { version = "2", features = [] } serde = { version = "1", features = ["derive"] } serde_json = "1" +tauri-plugin-dialog = "2.7.1" diff --git a/apps/windows-client/src-tauri/build.rs b/apps/windows-client/src-tauri/build.rs index 137d693..261851f 100644 --- a/apps/windows-client/src-tauri/build.rs +++ b/apps/windows-client/src-tauri/build.rs @@ -1,4 +1,3 @@ fn main() { tauri_build::build(); } - diff --git a/apps/windows-client/src-tauri/capabilities/default.json b/apps/windows-client/src-tauri/capabilities/default.json index b3044eb..eb4bbd8 100644 --- a/apps/windows-client/src-tauri/capabilities/default.json +++ b/apps/windows-client/src-tauri/capabilities/default.json @@ -3,5 +3,5 @@ "identifier": "default", "description": "Default capability for the main VPN Proxy Windows shell. Task 8 keeps helper/install launch explicit: no shell or sidecar permission is granted here until a packaged helper is declared.", "windows": ["main"], - "permissions": ["core:default"] + "permissions": ["core:default", "dialog:allow-open"] } diff --git a/apps/windows-client/src-tauri/gen/schemas/acl-manifests.json b/apps/windows-client/src-tauri/gen/schemas/acl-manifests.json index 0eebfc4..f2f210a 100644 --- a/apps/windows-client/src-tauri/gen/schemas/acl-manifests.json +++ b/apps/windows-client/src-tauri/gen/schemas/acl-manifests.json @@ -1 +1 @@ -{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener","allow-supports-multiple-windows"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-supports-multiple-windows":{"identifier":"allow-supports-multiple-windows","description":"Enables the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":["supports_multiple_windows"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-supports-multiple-windows":{"identifier":"deny-supports-multiple-windows","description":"Denies the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["supports_multiple_windows"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-icon-with-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-icon-with-as-template":{"identifier":"allow-set-icon-with-as-template","description":"Enables the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_with_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-icon-with-as-template":{"identifier":"deny-set-icon-with-as-template","description":"Denies the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_with_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-activity-name","allow-scene-identifier","allow-internal-toggle-maximize"]},"permissions":{"allow-activity-name":{"identifier":"allow-activity-name","description":"Enables the activity_name command without any pre-configured scope.","commands":{"allow":["activity_name"],"deny":[]}},"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-scene-identifier":{"identifier":"allow-scene-identifier","description":"Enables the scene_identifier command without any pre-configured scope.","commands":{"allow":["scene_identifier"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-activity-name":{"identifier":"deny-activity-name","description":"Denies the activity_name command without any pre-configured scope.","commands":{"allow":[],"deny":["activity_name"]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-scene-identifier":{"identifier":"deny-scene-identifier","description":"Denies the scene_identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["scene_identifier"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener","allow-supports-multiple-windows"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-supports-multiple-windows":{"identifier":"allow-supports-multiple-windows","description":"Enables the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":["supports_multiple_windows"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-supports-multiple-windows":{"identifier":"deny-supports-multiple-windows","description":"Denies the supports_multiple_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["supports_multiple_windows"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-icon-with-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-icon-with-as-template":{"identifier":"allow-set-icon-with-as-template","description":"Enables the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_with_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-icon-with-as-template":{"identifier":"deny-set-icon-with-as-template","description":"Denies the set_icon_with_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_with_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-activity-name","allow-scene-identifier","allow-internal-toggle-maximize"]},"permissions":{"allow-activity-name":{"identifier":"allow-activity-name","description":"Enables the activity_name command without any pre-configured scope.","commands":{"allow":["activity_name"],"deny":[]}},"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-scene-identifier":{"identifier":"allow-scene-identifier","description":"Enables the scene_identifier command without any pre-configured scope.","commands":{"allow":["scene_identifier"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-activity-name":{"identifier":"deny-activity-name","description":"Denies the activity_name command without any pre-configured scope.","commands":{"allow":[],"deny":["activity_name"]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-scene-identifier":{"identifier":"deny-scene-identifier","description":"Denies the scene_identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["scene_identifier"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)","commands":{"allow":["message"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)","commands":{"allow":["message"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)","commands":{"allow":[],"deny":["message"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)","commands":{"allow":[],"deny":["message"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/apps/windows-client/src-tauri/gen/schemas/capabilities.json b/apps/windows-client/src-tauri/gen/schemas/capabilities.json index 48b92d1..62e9233 100644 --- a/apps/windows-client/src-tauri/gen/schemas/capabilities.json +++ b/apps/windows-client/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{"default":{"identifier":"default","description":"Default capability for the main VPN Proxy Windows shell. Task 8 keeps helper/install launch explicit: no shell or sidecar permission is granted here until a packaged helper is declared.","local":true,"windows":["main"],"permissions":["core:default"]}} \ No newline at end of file +{"default":{"identifier":"default","description":"Default capability for the main VPN Proxy Windows shell. Task 8 keeps helper/install launch explicit: no shell or sidecar permission is granted here until a packaged helper is declared.","local":true,"windows":["main"],"permissions":["core:default","dialog:allow-open"]}} \ No newline at end of file diff --git a/apps/windows-client/src-tauri/gen/schemas/desktop-schema.json b/apps/windows-client/src-tauri/gen/schemas/desktop-schema.json index 3286645..24c9001 100644 --- a/apps/windows-client/src-tauri/gen/schemas/desktop-schema.json +++ b/apps/windows-client/src-tauri/gen/schemas/desktop-schema.json @@ -2191,6 +2191,72 @@ "type": "string", "const": "core:window:deny-unminimize", "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`", + "type": "string", + "const": "dialog:default", + "markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`" + }, + { + "description": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", + "type": "string", + "const": "dialog:allow-ask", + "markdownDescription": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)" + }, + { + "description": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", + "type": "string", + "const": "dialog:allow-confirm", + "markdownDescription": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)" + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message", + "markdownDescription": "Enables the message command without any pre-configured scope." + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open", + "markdownDescription": "Enables the open command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", + "type": "string", + "const": "dialog:deny-ask", + "markdownDescription": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)" + }, + { + "description": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", + "type": "string", + "const": "dialog:deny-confirm", + "markdownDescription": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)" + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message", + "markdownDescription": "Denies the message command without any pre-configured scope." + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open", + "markdownDescription": "Denies the open command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." } ] }, diff --git a/apps/windows-client/src-tauri/gen/schemas/windows-schema.json b/apps/windows-client/src-tauri/gen/schemas/windows-schema.json index 3286645..24c9001 100644 --- a/apps/windows-client/src-tauri/gen/schemas/windows-schema.json +++ b/apps/windows-client/src-tauri/gen/schemas/windows-schema.json @@ -2191,6 +2191,72 @@ "type": "string", "const": "core:window:deny-unminimize", "markdownDescription": "Denies the unminimize command without any pre-configured scope." + }, + { + "description": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`", + "type": "string", + "const": "dialog:default", + "markdownDescription": "This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n\n#### This default permission set includes:\n\n- `allow-message`\n- `allow-save`\n- `allow-open`" + }, + { + "description": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", + "type": "string", + "const": "dialog:allow-ask", + "markdownDescription": "Enables the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)" + }, + { + "description": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)", + "type": "string", + "const": "dialog:allow-confirm", + "markdownDescription": "Enables the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `allow-message` and will be removed in v3)" + }, + { + "description": "Enables the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-message", + "markdownDescription": "Enables the message command without any pre-configured scope." + }, + { + "description": "Enables the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-open", + "markdownDescription": "Enables the open command without any pre-configured scope." + }, + { + "description": "Enables the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:allow-save", + "markdownDescription": "Enables the save command without any pre-configured scope." + }, + { + "description": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", + "type": "string", + "const": "dialog:deny-ask", + "markdownDescription": "Denies the ask command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)" + }, + { + "description": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)", + "type": "string", + "const": "dialog:deny-confirm", + "markdownDescription": "Denies the confirm command without any pre-configured scope. (**DEPRECATED**: This is now an alias to `deny-message` and will be removed in v3)" + }, + { + "description": "Denies the message command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-message", + "markdownDescription": "Denies the message command without any pre-configured scope." + }, + { + "description": "Denies the open command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-open", + "markdownDescription": "Denies the open command without any pre-configured scope." + }, + { + "description": "Denies the save command without any pre-configured scope.", + "type": "string", + "const": "dialog:deny-save", + "markdownDescription": "Denies the save command without any pre-configured scope." } ] }, diff --git a/apps/windows-client/src-tauri/src/adapters/proxifyre.rs b/apps/windows-client/src-tauri/src/adapters/proxifyre.rs index be219e9..2839bbc 100644 --- a/apps/windows-client/src-tauri/src/adapters/proxifyre.rs +++ b/apps/windows-client/src-tauri/src/adapters/proxifyre.rs @@ -1,3 +1,8 @@ +#[cfg(not(test))] +use crate::adapters::proxy_router::{ + ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, + ProxyRouterRequest, +}; use crate::models::{ ComponentId, ComponentState, ComponentStatus, Profile, ProfileItemType, Protocol, ProxyProtocol, Target, @@ -7,11 +12,6 @@ use crate::proxy_router::{ ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, ProxyRouterRequest, }; -#[cfg(not(test))] -use crate::adapters::proxy_router::{ - ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, - ProxyRouterRequest, -}; use serde::{Deserialize, Serialize}; pub const PROXIFYRE_ADAPTER_ID: &str = "proxifyre"; @@ -45,7 +45,10 @@ impl ProxiFyreAdapter { if app_names.is_empty() { return Err(ProxyRouterError::new( ProxyRouterErrorKind::EmptyProfileItems, - format!("В профиле '{}' нет приложений для маршрутизации", profile.id), + format!( + "В профиле '{}' нет приложений для маршрутизации", + profile.id + ), )); } diff --git a/apps/windows-client/src-tauri/src/adapters/singbox.rs b/apps/windows-client/src-tauri/src/adapters/singbox.rs index bc4f08a..85aa19a 100644 --- a/apps/windows-client/src-tauri/src/adapters/singbox.rs +++ b/apps/windows-client/src-tauri/src/adapters/singbox.rs @@ -206,7 +206,10 @@ impl SingBoxConfigChecker for SingBoxCommandChecker { let _ = fs::remove_file(&config_path); SingBoxConfigError::new( SingBoxConfigErrorKind::CheckFailed, - format!("Не удалось выполнить '{} check': {error}", binary_path.display()), + format!( + "Не удалось выполнить '{} check': {error}", + binary_path.display() + ), ) })?; let _ = fs::remove_file(&config_path); @@ -320,14 +323,20 @@ fn ensure_local_singbox_target( else { return Err(SingBoxConfigError::new( SingBoxConfigErrorKind::MissingRequiredComponent, - format!("Локальная цель '{}' требует состояние компонента sing-box", target.id), + format!( + "Локальная цель '{}' требует состояние компонента sing-box", + target.id + ), )); }; if !component_is_running(status) { return Err(SingBoxConfigError::new( SingBoxConfigErrorKind::RequiredComponentNotRunning, - format!("Локальная цель '{}' требует установленный и запущенный sing-box", target.id), + format!( + "Локальная цель '{}' требует установленный и запущенный sing-box", + target.id + ), )); } diff --git a/apps/windows-client/src-tauri/src/commands.rs b/apps/windows-client/src-tauri/src/commands.rs index cfe4f86..10db9c7 100644 --- a/apps/windows-client/src-tauri/src/commands.rs +++ b/apps/windows-client/src-tauri/src/commands.rs @@ -5,13 +5,6 @@ use crate::adapters::proxy_router::{ ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, ProxyRouterRequest, }; -#[cfg(test)] -use crate::proxifyre::ProxiFyreAdapter; -#[cfg(test)] -use crate::proxy_router::{ - ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, - ProxyRouterRequest, -}; use crate::component_detection::{ detect_proxyfier_install, detect_proxyfier_install_with_host, proxyfier_component_from_detection, DetectedProxyfier, ProxyfierDetectionHost, @@ -22,9 +15,17 @@ use crate::models::{ ProfileInput, ProfileItem, ProfileItemInput, ProfileItemType, Protocol, ProxyProtocol, Target, TargetInput, TargetKind, }; +#[cfg(test)] +use crate::proxifyre::ProxiFyreAdapter; +#[cfg(test)] +use crate::proxy_router::{ + ProxyRouterAdapter, ProxyRouterError, ProxyRouterErrorKind, ProxyRouterGeneratedConfig, + ProxyRouterRequest, +}; use crate::storage::{default_config_root, JsonStorage}; use crate::validation::{normalize_profile, normalize_target, ValidationError}; use serde::{Deserialize, Serialize}; +use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; @@ -101,6 +102,14 @@ pub struct StatusResponse { pub generated_config_path: String, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SavedStateResponse { + pub profiles: Vec, + pub targets: Vec, + pub generated_config_path: String, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProfileInputDto { @@ -321,8 +330,20 @@ where } #[tauri::command] -pub fn get_status(state: tauri::State<'_, CommandState>) -> Result { - build_status(&state.storage()) +pub async fn get_status( + state: tauri::State<'_, CommandState>, +) -> Result { + let storage = state.storage(); + tauri::async_runtime::spawn_blocking(move || build_status(&storage)) + .await + .map_err(background_task_error)? +} + +#[tauri::command] +pub fn get_saved_state( + state: tauri::State<'_, CommandState>, +) -> Result { + read_saved_state(&state.storage()) } #[tauri::command] @@ -354,10 +375,13 @@ pub fn save_target( } #[tauri::command] -pub fn get_components( +pub async fn get_components( state: tauri::State<'_, CommandState>, ) -> Result, CommandError> { - read_components(&state.storage()) + let storage = state.storage(); + tauri::async_runtime::spawn_blocking(move || read_components(&storage)) + .await + .map_err(background_task_error)? } #[tauri::command] @@ -389,7 +413,10 @@ pub fn get_logs( #[tauri::command] pub fn open_config_location(state: tauri::State<'_, CommandState>) -> Result { let storage = state.storage(); - let generated_path = storage.paths().generated_dir.join("proxifyre-app-config.json"); + let generated_path = storage + .paths() + .generated_dir + .join("proxifyre-app-config.json"); let config_path = detect_proxyfier_install() .and_then(|detected| detected.config_path) .filter(|path| path.exists()) @@ -403,6 +430,20 @@ pub fn open_config_location(state: tauri::State<'_, CommandState>) -> Result Result { + tauri::async_runtime::spawn_blocking(|| control_proxifyre_service(ServiceControlAction::Start)) + .await + .map_err(background_task_error)? +} + +#[tauri::command] +pub async fn stop_proxifyre_service() -> Result { + tauri::async_runtime::spawn_blocking(|| control_proxifyre_service(ServiceControlAction::Stop)) + .await + .map_err(background_task_error)? +} + pub fn build_status(storage: &JsonStorage) -> Result { let profiles = storage.read_profiles().map_err(storage_error)?; let targets = storage.read_targets().map_err(storage_error)?; @@ -426,7 +467,11 @@ pub fn build_status(storage: &JsonStorage) -> Result Result, Com .map(|entries| entries.iter().map(ActivityEntryDto::from).collect()) } +pub fn read_saved_state(storage: &JsonStorage) -> Result { + Ok(SavedStateResponse { + profiles: read_profiles(storage)?, + targets: read_targets(storage)?, + generated_config_path: storage + .paths() + .generated_dir + .join("proxifyre-app-config.json") + .display() + .to_string(), + }) +} + pub fn resolve_preview( input: ProfileInputDto, ) -> Result { @@ -608,7 +666,10 @@ fn default_components() -> Vec { version: None, path: None, problems: Vec::new(), - actions: vec!["Открыть журнал".to_string(), "Скопировать диагностику".to_string()], + actions: vec![ + "Открыть журнал".to_string(), + "Скопировать диагностику".to_string(), + ], }, ComponentStatus { id: ComponentId::Proxyfier, @@ -720,6 +781,386 @@ fn open_folder(path: &Path) -> Result { Ok(path.display().to_string()) } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ServiceControlAction { + Start, + Stop, +} + +impl ServiceControlAction { + fn error_code(self) -> &'static str { + match self { + ServiceControlAction::Start => "proxifyre_service_start_failed", + ServiceControlAction::Stop => "proxifyre_service_stop_failed", + } + } + + fn label(self) -> &'static str { + match self { + ServiceControlAction::Start => "запустить", + ServiceControlAction::Stop => "остановить", + } + } +} + +fn control_proxifyre_service( + action: ServiceControlAction, +) -> Result { + let Some(detected) = detect_proxyfier_install() else { + return Err(CommandError::new( + "proxifyre_not_found", + "ProxiFyre не найден на компьютере.", + )); + }; + + run_proxifyre_service_command(action, &service_name_candidates(&detected))?; + let refreshed = detect_proxyfier_install(); + let component = proxyfier_component_from_detection(refreshed.as_ref()); + + Ok(ComponentStatusDto::from(&component)) +} + +fn service_name_candidates(detected: &DetectedProxyfier) -> Vec { + let mut names = Vec::new(); + + if let Some(service_name) = &detected.service_name { + names.push(service_name.clone()); + } + for service_name in ["ProxiFyreService", "ProxiFyre"] { + if !names + .iter() + .any(|existing| existing.eq_ignore_ascii_case(service_name)) + { + names.push(service_name.to_string()); + } + } + + names +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct ServiceCommandOutput { + success: bool, + code: String, + service_name: Option, + status: Option, + process_id: Option, +} + +fn run_proxifyre_service_command( + action: ServiceControlAction, + service_names: &[String], +) -> Result<(), CommandError> { + let names = service_names + .iter() + .map(|name| format!("'{}'", escape_powershell_single(name))) + .collect::>() + .join(", "); + let action_name = match action { + ServiceControlAction::Start => "start", + ServiceControlAction::Stop => "stop", + }; + let script = format!( + r#" +$ErrorActionPreference = 'Stop' +$names = @({names}) +$action = '{action_name}' +$service = $null + +function Find-ProxiFyreService {{ + foreach ($name in $names) {{ + $candidate = Get-Service -Name $name -ErrorAction SilentlyContinue + if ($null -ne $candidate) {{ return $candidate }} + }} + + return Get-Service | + Where-Object {{ $_.Name -match 'ProxiFyre|Proxifyre' -or $_.DisplayName -match 'ProxiFyre|Proxifyre' }} | + Select-Object -First 1 +}} + +function Get-ServiceProcessId([string]$name) {{ + $escapedName = $name.Replace("'", "''") + $record = Get-CimInstance Win32_Service -Filter "Name='$escapedName'" -ErrorAction SilentlyContinue + if ($null -eq $record) {{ return 0 }} + return [int]$record.ProcessId +}} + +function Get-ServiceStatus([string]$name) {{ + $current = Get-Service -Name $name -ErrorAction SilentlyContinue + if ($null -eq $current) {{ return $null }} + return $current.Status.ToString() +}} + +function Write-ServiceResult([bool]$success, [string]$code, [string]$status, [int]$processId) {{ + [PSCustomObject]@{{ + success = $success + code = $code + serviceName = if ($null -ne $service) {{ $service.Name }} else {{ $null }} + status = $status + processId = $processId + }} | ConvertTo-Json -Compress + exit 0 +}} + +$service = Find-ProxiFyreService +if ($null -eq $service) {{ + Write-ServiceResult $false 'service_not_found' $null 0 +}} + +$status = $service.Status.ToString() +$processId = Get-ServiceProcessId $service.Name + +if ($action -eq 'start') {{ + if ($status -eq 'Running') {{ + Write-ServiceResult $true 'already_running' $status $processId + }} + + try {{ + Start-Service -Name $service.Name -ErrorAction Stop + $service = Get-Service -Name $service.Name + $service.WaitForStatus('Running', [TimeSpan]::FromSeconds(15)) + }} catch {{ + Write-ServiceResult $false 'start_failed' (Get-ServiceStatus $service.Name) (Get-ServiceProcessId $service.Name) + }} + + Write-ServiceResult ($service.Status -eq 'Running') 'started' $service.Status.ToString() (Get-ServiceProcessId $service.Name) +}} + +if ($status -eq 'Stopped') {{ + Write-ServiceResult $true 'already_stopped' $status $processId +}} + +try {{ + if ($service.CanStop) {{ + Stop-Service -Name $service.Name -Force -ErrorAction Stop + }} +}} catch {{}} + +try {{ + $service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue + if ($null -ne $service -and $service.Status -ne 'Stopped') {{ + $null = & sc.exe stop $service.Name 2>$null + }} +}} catch {{}} + +try {{ + $service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue + if ($null -ne $service -and $service.Status -ne 'Stopped') {{ + $service.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(8)) + }} +}} catch {{}} + +$status = Get-ServiceStatus $service.Name +$processId = Get-ServiceProcessId $service.Name +if ($status -ne 'Stopped' -and $processId -gt 0) {{ + try {{ + $null = & taskkill.exe /PID $processId /F 2>$null + Start-Sleep -Milliseconds 700 + $service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue + if ($null -ne $service) {{ + $service.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(8)) + }} + }} catch {{}} +}} + +$status = Get-ServiceStatus $service.Name +$processId = Get-ServiceProcessId $service.Name +if ($status -eq 'Stopped') {{ + Write-ServiceResult $true 'stopped' $status $processId +}} + +Write-ServiceResult $false 'stop_failed' $status $processId +"# + ); + + let output = Command::new("powershell") + .args([ + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", + "Bypass", + "-Command", + script.as_str(), + ]) + .output() + .map_err(|error| { + CommandError::new( + action.error_code(), + format!("Не удалось {} службу ProxiFyre: {error}", action.label()), + ) + })?; + + let result = parse_service_command_output(&output.stdout).ok_or_else(|| { + CommandError::new( + action.error_code(), + service_script_failed_message(action, output.status.code()), + ) + })?; + + if result.success { + return Ok(()); + } + + if matches!(result.code.as_str(), "start_failed" | "stop_failed") { + run_elevated_proxifyre_service_command(action, service_names, &result)?; + return Ok(()); + } + + Err(CommandError::new( + action.error_code(), + service_command_failed_message(action, &result), + )) +} + +fn run_elevated_proxifyre_service_command( + action: ServiceControlAction, + service_names: &[String], + direct_result: &ServiceCommandOutput, +) -> Result<(), CommandError> { + let script_path = write_elevated_service_script(action, service_names)?; + let launch_script = format!( + "$p = Start-Process -FilePath 'powershell.exe' -Verb RunAs -Wait -PassThru -WindowStyle Hidden -ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File','{}'); exit $p.ExitCode", + escape_powershell_single(&script_path.display().to_string()) + ); + let output = Command::new("powershell") + .args([ + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", + "Bypass", + "-Command", + launch_script.as_str(), + ]) + .output(); + + let _ = fs::remove_file(&script_path); + + match output { + Ok(output) if output.status.success() => Ok(()), + Ok(output) => Err(CommandError::new( + action.error_code(), + elevated_service_failed_message(action, direct_result, output.status.code()), + )), + Err(error) => Err(CommandError::new( + action.error_code(), + format!( + "Не удалось запросить права администратора, чтобы {} службу ProxiFyre: {error}", + action.label() + ), + )), + } +} + +fn write_elevated_service_script( + action: ServiceControlAction, + service_names: &[String], +) -> Result { + let nonce = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_millis()) + .unwrap_or(0); + let script_path = env::temp_dir().join(format!("vpn-proxy-proxifyre-service-{nonce}.ps1")); + let script = elevated_service_script(action, service_names); + + fs::write(&script_path, script).map_err(|error| { + CommandError::new( + action.error_code(), + format!( + "Не удалось подготовить временный скрипт для управления ProxiFyre '{}': {error}", + script_path.display() + ), + ) + })?; + + Ok(script_path) +} + +fn elevated_service_script(action: ServiceControlAction, service_names: &[String]) -> String { + let names = service_names + .iter() + .map(|name| format!("'{}'", escape_powershell_single(name))) + .collect::>() + .join(", "); + let action_name = match action { + ServiceControlAction::Start => "start", + ServiceControlAction::Stop => "stop", + }; + + format!( + r#" +$ErrorActionPreference = 'SilentlyContinue' +$names = @({names}) +$action = '{action_name}' +$service = $null + +foreach ($name in $names) {{ + $service = Get-Service -Name $name -ErrorAction SilentlyContinue + if ($null -ne $service) {{ break }} +}} + +if ($null -eq $service) {{ + $service = Get-Service | + Where-Object {{ $_.Name -match 'ProxiFyre|Proxifyre' -or $_.DisplayName -match 'ProxiFyre|Proxifyre' }} | + Select-Object -First 1 +}} + +if ($null -eq $service) {{ exit 2 }} + +function Get-ServiceProcessId([string]$name) {{ + $escapedName = $name.Replace("'", "''") + $record = Get-CimInstance Win32_Service -Filter "Name='$escapedName'" -ErrorAction SilentlyContinue + if ($null -eq $record) {{ return 0 }} + return [int]$record.ProcessId +}} + +if ($action -eq 'start') {{ + if ($service.Status -eq 'Running') {{ exit 0 }} + Start-Service -Name $service.Name -ErrorAction SilentlyContinue + $service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue + if ($null -ne $service) {{ + try {{ $service.WaitForStatus('Running', [TimeSpan]::FromSeconds(15)) }} catch {{}} + if ($service.Status -eq 'Running') {{ exit 0 }} + }} + exit 3 +}} + +if ($service.Status -eq 'Stopped') {{ exit 0 }} + +if ($service.CanStop) {{ + Stop-Service -Name $service.Name -Force -ErrorAction SilentlyContinue +}} + +$service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue +if ($null -ne $service -and $service.Status -ne 'Stopped') {{ + $null = & sc.exe stop $service.Name 2>$null +}} + +$service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue +if ($null -ne $service -and $service.Status -ne 'Stopped') {{ + try {{ $service.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(8)) }} catch {{}} +}} + +$service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue +if ($null -ne $service -and $service.Status -ne 'Stopped') {{ + $processId = Get-ServiceProcessId $service.Name + if ($processId -gt 0) {{ + $null = & taskkill.exe /PID $processId /F 2>$null + Start-Sleep -Milliseconds 700 + $service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue + if ($null -ne $service) {{ + try {{ $service.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(8)) }} catch {{}} + }} + }} +}} + +$service = Get-Service -Name $service.Name -ErrorAction SilentlyContinue +if ($null -eq $service -or $service.Status -eq 'Stopped') {{ exit 0 }} +exit 4 +"# + ) +} + fn apply_to_detected_proxyfier( request: HelperApplyRequest<'_>, detected: &DetectedProxyfier, @@ -832,6 +1273,104 @@ fn storage_error(error: std::io::Error) -> CommandError { CommandError::new("storage_error", error.to_string()) } +fn background_task_error(error: impl std::fmt::Display) -> CommandError { + CommandError::new( + "background_task_failed", + format!("Фоновая проверка не завершилась: {error}"), + ) +} + +fn parse_service_command_output(stdout: &[u8]) -> Option { + let stdout = String::from_utf8_lossy(stdout); + let payload = stdout + .lines() + .rev() + .map(str::trim) + .find(|line| line.starts_with('{') && line.ends_with('}'))?; + + serde_json::from_str(payload).ok() +} + +fn service_script_failed_message(action: ServiceControlAction, exit_code: Option) -> String { + let exit_code = exit_code + .map(|code| format!(" Код выхода PowerShell: {code}.")) + .unwrap_or_default(); + + format!( + "Не удалось {} службу ProxiFyre: команда управления службой не вернула корректный результат.{exit_code}", + action.label() + ) +} + +fn service_command_failed_message( + action: ServiceControlAction, + result: &ServiceCommandOutput, +) -> String { + let service_name = result + .service_name + .as_deref() + .filter(|value| !value.trim().is_empty()) + .unwrap_or("ProxiFyre"); + let status = result + .status + .as_deref() + .filter(|value| !value.trim().is_empty()) + .unwrap_or("неизвестен"); + let pid = result + .process_id + .filter(|value| *value > 0) + .map(|value| format!(", PID: {value}")) + .unwrap_or_default(); + + match result.code.as_str() { + "service_not_found" => "Служба ProxiFyre не найдена.".to_string(), + "start_failed" => format!( + "Не удалось запустить службу {service_name}. Текущий статус: {status}{pid}. Попробуй запустить приложение от имени администратора." + ), + "stop_failed" => format!( + "Не удалось остановить службу {service_name} даже после принудительной попытки. Текущий статус: {status}{pid}. Запусти приложение от имени администратора или останови службу вручную в services.msc." + ), + _ => format!( + "Не удалось {} службу {service_name}. Текущий статус: {status}{pid}.", + action.label() + ), + } +} + +fn elevated_service_failed_message( + action: ServiceControlAction, + direct_result: &ServiceCommandOutput, + exit_code: Option, +) -> String { + let service_name = direct_result + .service_name + .as_deref() + .filter(|value| !value.trim().is_empty()) + .unwrap_or("ProxiFyre"); + let status = direct_result + .status + .as_deref() + .filter(|value| !value.trim().is_empty()) + .unwrap_or("неизвестен"); + let pid = direct_result + .process_id + .filter(|value| *value > 0) + .map(|value| format!(", PID: {value}")) + .unwrap_or_default(); + let exit_code = exit_code + .map(|code| format!(" Код elevated-команды: {code}.")) + .unwrap_or_default(); + + format!( + "Не удалось {} службу {service_name} даже после запроса прав администратора. До запроса UAC статус был: {status}{pid}.{exit_code} Если появлялось окно UAC, проверь, что оно было подтверждено.", + action.label() + ) +} + +fn escape_powershell_single(value: &str) -> String { + value.replace('\'', "''") +} + fn validation_error(errors: Vec) -> CommandError { CommandError::with_details( "validation_error", diff --git a/apps/windows-client/src-tauri/src/component_detection.rs b/apps/windows-client/src-tauri/src/component_detection.rs index c964735..cad06b4 100644 --- a/apps/windows-client/src-tauri/src/component_detection.rs +++ b/apps/windows-client/src-tauri/src/component_detection.rs @@ -94,9 +94,7 @@ pub fn detect_proxyfier_install_with_host( .next() } -pub fn proxyfier_component_from_detection( - detected: Option<&DetectedProxyfier>, -) -> ComponentStatus { +pub fn proxyfier_component_from_detection(detected: Option<&DetectedProxyfier>) -> ComponentStatus { match detected { Some(proxyfier) => detected_proxyfier_component(proxyfier), None => missing_proxyfier_component(), @@ -115,7 +113,7 @@ fn detected_proxyfier_component(proxyfier: &DetectedProxyfier) -> ComponentStatu vec![ "Применить сгенерированный конфиг".to_string(), "Открыть папку конфига".to_string(), - "Перезапустить".to_string(), + "Остановить".to_string(), ] } else { vec![ @@ -255,7 +253,8 @@ fn push_env_candidate( fn push_candidate(candidates: &mut Vec, candidate: ProxyfierCandidate) { if !candidates.iter().any(|existing| { - existing.engine == candidate.engine && same_path(&existing.install_dir, &candidate.install_dir) + existing.engine == candidate.engine + && same_path(&existing.install_dir, &candidate.install_dir) }) { candidates.push(candidate); } diff --git a/apps/windows-client/src-tauri/src/main.rs b/apps/windows-client/src-tauri/src/main.rs index 37f0d3d..3a41b84 100644 --- a/apps/windows-client/src-tauri/src/main.rs +++ b/apps/windows-client/src-tauri/src/main.rs @@ -1,8 +1,8 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] mod activity; -mod component_detection; mod commands; +mod component_detection; mod models; mod storage; mod validation; @@ -24,10 +24,12 @@ pub(crate) mod proxy_router { fn main() { tauri::Builder::default() + .plugin(tauri_plugin_dialog::init()) .manage(commands::CommandState::default()) .invoke_handler(tauri::generate_handler![ commands::get_status, commands::get_profiles, + commands::get_saved_state, commands::save_profile, commands::get_targets, commands::save_target, @@ -35,7 +37,9 @@ fn main() { commands::resolve_profile_preview, commands::apply_profiles, commands::get_logs, - commands::open_config_location + commands::open_config_location, + commands::start_proxifyre_service, + commands::stop_proxifyre_service ]) .run(tauri::generate_context!()) .expect("не удалось запустить клиент VPN Proxy для Windows"); diff --git a/apps/windows-client/src-tauri/src/validation.rs b/apps/windows-client/src-tauri/src/validation.rs index 2e0cc42..854fa48 100644 --- a/apps/windows-client/src-tauri/src/validation.rs +++ b/apps/windows-client/src-tauri/src/validation.rs @@ -45,12 +45,7 @@ fn slug(value: &str, fallback: &str) -> String { } fn process_name(value: &str) -> String { - let base = value - .trim() - .rsplit(['\\', '/']) - .next() - .unwrap_or("") - .trim(); + let base = value.trim().rsplit(['\\', '/']).next().unwrap_or("").trim(); base.strip_suffix(".exe") .or_else(|| base.strip_suffix(".EXE")) .unwrap_or(base) @@ -62,7 +57,10 @@ pub fn parse_protocol(value: &str) -> Result { match value.trim().to_ascii_uppercase().as_str() { "TCP" => Ok(Protocol::Tcp), "UDP" => Ok(Protocol::Udp), - _ => Err(error("protocols", format!("Неподдерживаемый протокол: {value}"))), + _ => Err(error( + "protocols", + format!("Неподдерживаемый протокол: {value}"), + )), } } @@ -71,7 +69,10 @@ pub fn parse_profile_item_type(value: &str) -> Result Ok(ProfileItemType::Process), "folder" => Ok(ProfileItemType::Folder), "exe" => Ok(ProfileItemType::Exe), - _ => Err(error("items.type", format!("Неподдерживаемый тип элемента: {value}"))), + _ => Err(error( + "items.type", + format!("Неподдерживаемый тип элемента: {value}"), + )), } } @@ -149,8 +150,8 @@ pub fn normalize_profile(input: ProfileInput) -> ValidationResult { continue; } - let recursive = matches!(item_type, ProfileItemType::Folder) - && raw_item.recursive.unwrap_or(true); + let recursive = + matches!(item_type, ProfileItemType::Folder) && raw_item.recursive.unwrap_or(true); items.push(ProfileItem { item_type, value, diff --git a/apps/windows-client/src-tauri/tests/command_tests.rs b/apps/windows-client/src-tauri/tests/command_tests.rs index d01f948..32f5dc9 100644 --- a/apps/windows-client/src-tauri/tests/command_tests.rs +++ b/apps/windows-client/src-tauri/tests/command_tests.rs @@ -1,9 +1,9 @@ #[path = "../src/activity.rs"] mod activity; -#[path = "../src/component_detection.rs"] -mod component_detection; #[path = "../src/commands.rs"] mod commands; +#[path = "../src/component_detection.rs"] +mod component_detection; #[path = "../src/models.rs"] mod models; #[path = "../src/adapters/proxifyre.rs"] @@ -17,9 +17,9 @@ mod validation; use commands::{ apply_profiles_with_services, build_status, resolve_component_statuses, resolve_preview, - save_profile_to_storage, save_target_to_storage, Clock, CommandError, - DetectedProxyApplyHelper, HelperApplyRequest, HelperApplyResult, ProfileInputDto, - ProfileItemInputDto, ProxyApplyHelper, TargetInputDto, + save_profile_to_storage, save_target_to_storage, Clock, CommandError, DetectedProxyApplyHelper, + HelperApplyRequest, HelperApplyResult, ProfileInputDto, ProfileItemInputDto, ProxyApplyHelper, + TargetInputDto, }; use component_detection::{ DetectedProxyfier, ProxyfierDetectionHost, ProxyfierEngine, RegistryInstallEntry, @@ -240,8 +240,8 @@ fn detected_proxy_apply_helper_writes_proxifyre_app_config() { }) .expect("detected helper should apply"); - let applied = fs::read_to_string(install_dir.join("app-config.json")) - .expect("read applied app-config"); + let applied = + fs::read_to_string(install_dir.join("app-config.json")).expect("read applied app-config"); assert!(result.success); assert!(result.changed); @@ -276,7 +276,9 @@ fn detected_proxy_apply_helper_ignores_plain_proxifier_install() { assert!(result.success); assert!(result.changed); assert_eq!(result.action, "proxifyre.stage-generated-config"); - assert!(result.message.contains("совместимая установка ProxiFyre не найдена")); + assert!(result + .message + .contains("совместимая установка ProxiFyre не найдена")); cleanup(&root); } @@ -358,7 +360,10 @@ impl ProxyfierDetectionHost for DetectionHost { } fn normalize_path(path: &Path) -> String { - path.display().to_string().replace('/', "\\").to_ascii_lowercase() + path.display() + .to_string() + .replace('/', "\\") + .to_ascii_lowercase() } fn test_root(name: &str) -> PathBuf { diff --git a/apps/windows-client/src-tauri/tests/component_detection_tests.rs b/apps/windows-client/src-tauri/tests/component_detection_tests.rs index 7dce85b..7459fde 100644 --- a/apps/windows-client/src-tauri/tests/component_detection_tests.rs +++ b/apps/windows-client/src-tauri/tests/component_detection_tests.rs @@ -7,7 +7,7 @@ use component_detection::{ detect_proxyfier_install_with_host, proxyfier_component_from_detection, ProxyfierDetectionHost, ProxyfierEngine, RegistryInstallEntry, }; -use models::{ComponentState}; +use models::ComponentState; use std::{ collections::{HashMap, HashSet}, path::{Path, PathBuf}, @@ -25,7 +25,10 @@ fn detects_existing_proxifyre_from_registry_install_location() { assert_eq!(detected.engine, ProxyfierEngine::ProxiFyre); assert_eq!(detected.install_dir, PathBuf::from(r"C:\Tools\ProxiFyre")); - assert_eq!(detected.config_path, Some(PathBuf::from(r"C:\Tools\ProxiFyre\app-config.json"))); + assert_eq!( + detected.config_path, + Some(PathBuf::from(r"C:\Tools\ProxiFyre\app-config.json")) + ); assert!(detected.running); let component = proxyfier_component_from_detection(Some(&detected)); @@ -56,7 +59,10 @@ fn env_override_can_point_to_portable_proxifyre_install() { .expect("env override should be checked before common paths"); assert_eq!(detected.engine, ProxyfierEngine::ProxiFyre); - assert_eq!(detected.executable_path, PathBuf::from(r"D:\Portable\ProxiFyre\ProxiFyre.exe")); + assert_eq!( + detected.executable_path, + PathBuf::from(r"D:\Portable\ProxiFyre\ProxiFyre.exe") + ); } #[test] @@ -118,17 +124,16 @@ impl ProxyfierDetectionHost for MockHost { } fn path_exists(&self, path: &Path) -> bool { - self.paths.contains(&normalize_path(&path.display().to_string())) + self.paths + .contains(&normalize_path(&path.display().to_string())) } fn process_running(&self, process_name: &str) -> bool { - self.processes - .contains(&process_name.to_ascii_lowercase()) + self.processes.contains(&process_name.to_ascii_lowercase()) } fn service_running(&self, service_name: &str) -> bool { - self.services - .contains(&service_name.to_ascii_lowercase()) + self.services.contains(&service_name.to_ascii_lowercase()) } fn registry_install_entries(&self) -> Vec { diff --git a/apps/windows-client/src-tauri/tests/domain_tests.rs b/apps/windows-client/src-tauri/tests/domain_tests.rs index 76459c8..a06428f 100644 --- a/apps/windows-client/src-tauri/tests/domain_tests.rs +++ b/apps/windows-client/src-tauri/tests/domain_tests.rs @@ -124,7 +124,5 @@ fn rejects_malformed_target_fields() { assert!(error.iter().any(|item| item.field == "host")); assert!(error.iter().any(|item| item.field == "port")); assert!(error.iter().any(|item| item.field == "protocol")); - assert!(error - .iter() - .any(|item| item.field == "requires_component")); + assert!(error.iter().any(|item| item.field == "requires_component")); } diff --git a/apps/windows-client/src-tauri/tests/proxifyre_adapter_tests.rs b/apps/windows-client/src-tauri/tests/proxifyre_adapter_tests.rs index 2d062f1..1f67eaf 100644 --- a/apps/windows-client/src-tauri/tests/proxifyre_adapter_tests.rs +++ b/apps/windows-client/src-tauri/tests/proxifyre_adapter_tests.rs @@ -1,9 +1,9 @@ #[path = "../src/models.rs"] mod models; -#[path = "../src/adapters/proxy_router.rs"] -mod proxy_router; #[path = "../src/adapters/proxifyre.rs"] mod proxifyre; +#[path = "../src/adapters/proxy_router.rs"] +mod proxy_router; use models::{ ComponentId, ComponentState, ComponentStatus, Profile, ProfileItem, ProfileItemType, Protocol, @@ -33,7 +33,10 @@ fn generates_proxifyre_config_for_discord_external_socks5_target() { assert!(config.bypass_lan); assert_eq!(config.proxies.len(), 1); assert_eq!(config.proxies[0].app_names, vec!["Discord"]); - assert_eq!(config.proxies[0].socks5_proxy_endpoint, "192.168.50.111:8080"); + assert_eq!( + config.proxies[0].socks5_proxy_endpoint, + "192.168.50.111:8080" + ); assert_eq!(config.proxies[0].supported_protocols, vec!["TCP", "UDP"]); } @@ -57,6 +60,32 @@ fn skips_disabled_profiles_when_generating_proxifyre_config() { assert!(config.proxies.is_empty()); } +#[test] +fn includes_folder_paths_when_generating_proxifyre_config() { + let adapter = ProxiFyreAdapter::default(); + let mut profile = discord_profile("home-gateway"); + profile.items.push(ProfileItem { + item_type: ProfileItemType::Folder, + value: r"C:\Games\MyGame".to_string(), + recursive: true, + }); + let profiles = vec![profile]; + let targets = vec![external_socks5_target()]; + let components = Vec::new(); + + let generated = adapter + .generate_config(ProxyRouterRequest::new(&profiles, &targets, &components)) + .expect("folder paths should be accepted by ProxiFyre config generation"); + let config: ProxiFyreConfig = + serde_json::from_str(&generated.contents).expect("generated config json"); + + assert_eq!(generated.routed_apps, 2); + assert_eq!( + config.proxies[0].app_names, + vec!["Discord", r"C:\Games\MyGame"] + ); +} + #[test] fn blocks_local_singbox_target_when_required_component_is_missing() { let adapter = ProxiFyreAdapter::default(); diff --git a/apps/windows-client/src-tauri/tests/singbox_adapter_tests.rs b/apps/windows-client/src-tauri/tests/singbox_adapter_tests.rs index b1e6d4d..874acca 100644 --- a/apps/windows-client/src-tauri/tests/singbox_adapter_tests.rs +++ b/apps/windows-client/src-tauri/tests/singbox_adapter_tests.rs @@ -1,9 +1,9 @@ #[path = "../src/models.rs"] mod models; -#[path = "../src/adapters/proxy_router.rs"] -mod proxy_router; #[path = "../src/adapters/proxifyre.rs"] mod proxifyre; +#[path = "../src/adapters/proxy_router.rs"] +mod proxy_router; #[path = "../src/adapters/singbox.rs"] mod singbox; @@ -14,8 +14,8 @@ use models::{ use proxifyre::{ProxiFyreAdapter, ProxiFyreConfig}; use proxy_router::{ProxyRouterAdapter, ProxyRouterRequest}; use singbox::{ - SingBoxAdapter, SingBoxCheckResult, SingBoxConfig, SingBoxConfigChecker, - SingBoxConfigError, SingBoxConfigErrorKind, SingBoxGenerationRequest, SINGBOX_OUTPUT_FILE, + SingBoxAdapter, SingBoxCheckResult, SingBoxConfig, SingBoxConfigChecker, SingBoxConfigError, + SingBoxConfigErrorKind, SingBoxGenerationRequest, SINGBOX_OUTPUT_FILE, }; use std::{ cell::RefCell, @@ -116,7 +116,10 @@ fn blocks_local_singbox_config_when_component_is_not_running() { ) .expect_err("local sing-box target requires running component"); - assert_eq!(error.kind, SingBoxConfigErrorKind::RequiredComponentNotRunning); + assert_eq!( + error.kind, + SingBoxConfigErrorKind::RequiredComponentNotRunning + ); assert!(checker.calls.borrow().is_empty()); } @@ -129,11 +132,7 @@ fn propagates_failed_singbox_check_as_structured_error() { let error = adapter .generate_config( - SingBoxGenerationRequest::new( - &targets, - &components, - Some(Path::new("sing-box.exe")), - ), + SingBoxGenerationRequest::new(&targets, &components, Some(Path::new("sing-box.exe"))), &checker, ) .expect_err("failed sing-box check should block generated config"); @@ -156,7 +155,10 @@ fn external_proxifyre_apply_does_not_require_singbox_component() { serde_json::from_str(&generated.contents).expect("generated proxifyre json"); assert_eq!(config.proxies.len(), 1); - assert_eq!(config.proxies[0].socks5_proxy_endpoint, "192.168.50.111:8080"); + assert_eq!( + config.proxies[0].socks5_proxy_endpoint, + "192.168.50.111:8080" + ); } struct RecordingChecker { diff --git a/apps/windows-client/src-tauri/tests/storage_tests.rs b/apps/windows-client/src-tauri/tests/storage_tests.rs index a088c83..c7ef420 100644 --- a/apps/windows-client/src-tauri/tests/storage_tests.rs +++ b/apps/windows-client/src-tauri/tests/storage_tests.rs @@ -45,7 +45,10 @@ fn roundtrips_profiles_targets_components_and_activity() { assert_eq!(storage.read_profiles().expect("read profiles"), profiles); assert_eq!(storage.read_targets().expect("read targets"), targets); - assert_eq!(storage.read_components().expect("read components"), components); + assert_eq!( + storage.read_components().expect("read components"), + components + ); assert_eq!(storage.read_activity().expect("read activity"), activity); cleanup(&root); diff --git a/apps/windows-client/src/api/tauriCommands.ts b/apps/windows-client/src/api/tauriCommands.ts index 43a5698..45c87fa 100644 --- a/apps/windows-client/src/api/tauriCommands.ts +++ b/apps/windows-client/src/api/tauriCommands.ts @@ -27,6 +27,12 @@ export interface StatusResponse { generatedConfigPath: string; } +export interface SavedStateResponse { + profiles: Profile[]; + targets: Target[]; + generatedConfigPath: string; +} + export interface HelperApplyResult { success: boolean; changed: boolean; @@ -50,6 +56,10 @@ export function getStatus(): Promise { return invoke('get_status'); } +export function getSavedState(): Promise { + return invoke('get_saved_state'); +} + export function getProfiles(): Promise { return invoke('get_profiles'); } @@ -77,3 +87,11 @@ export function applyProfiles(): Promise { export function openConfigLocation(): Promise { return invoke('open_config_location'); } + +export function startProxiFyreService(): Promise { + return invoke('start_proxifyre_service'); +} + +export function stopProxiFyreService(): Promise { + return invoke('stop_proxifyre_service'); +} diff --git a/apps/windows-client/src/app/App.tsx b/apps/windows-client/src/app/App.tsx index 3075343..c24dbe5 100644 --- a/apps/windows-client/src/app/App.tsx +++ b/apps/windows-client/src/app/App.tsx @@ -1,18 +1,21 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import { open } from '@tauri-apps/plugin-dialog'; +import { Cpu, FileCode2, FolderOpen } from 'lucide-react'; import { applyProfiles, getComponents, - getProfiles, - getStatus, - getTargets, + getSavedState, openConfigLocation, saveProfile, saveTarget, + startProxiFyreService, + stopProxiFyreService, type ApplyProfilesResponse, } from '../api/tauriCommands'; import type { ComponentStatus, Profile, ProfileItemInput, ProfileItemType, Target } from '../domain/types'; -type DraftItemType = Extract; +type DraftItemType = Extract; +type ServiceVisualState = 'active' | 'settling' | null; interface DraftItem { id: string; @@ -26,8 +29,14 @@ interface Notice { text: string; } +interface LogEntry extends Notice { + id: string; + at: number; +} + const MAIN_TARGET_ID = 'main-proxy'; const MAIN_PROFILE_ID = 'main-profile'; +const LOG_VISIBLE_MS = 6500; const fallbackComponents: ComponentStatus[] = [ { @@ -47,50 +56,63 @@ export function App() { const [targetId, setTargetId] = useState(MAIN_TARGET_ID); const [items, setItems] = useState([]); const [loadedProfiles, setLoadedProfiles] = useState([]); - const [newItemType, setNewItemType] = useState('process'); - const [newItemValue, setNewItemValue] = useState(''); + const [isProcessInputOpen, setIsProcessInputOpen] = useState(false); + const [processInput, setProcessInput] = useState(''); + const [pickerAction, setPickerAction] = useState<'exe' | 'folder' | null>(null); const [components, setComponents] = useState(fallbackComponents); const [generatedConfigPath, setGeneratedConfigPath] = useState(''); - const [notice, setNotice] = useState(null); + const [logEntries, setLogEntries] = useState([]); + const [activeLogId, setActiveLogId] = useState(null); + const [isLogOpen, setIsLogOpen] = useState(false); const [isLoading, setIsLoading] = useState(true); + const [isDetectingComponents, setIsDetectingComponents] = useState(true); const [isApplying, setIsApplying] = useState(false); const [isOpeningConfig, setIsOpeningConfig] = useState(false); + const [serviceAction, setServiceAction] = useState<'start' | 'stop' | null>(null); + const [serviceVisualState, setServiceVisualState] = useState(null); + const serviceVisualTimerRef = useRef(null); const proxyfier = useMemo( () => components.find((component) => component.id === 'proxyfier'), [components], ); + const activeLog = useMemo( + () => logEntries.find((entry) => entry.id === activeLogId) ?? null, + [activeLogId, logEntries], + ); + const finderStateClass = isDetectingComponents ? 'checking' : proxyfier?.installed ? 'found' : 'missing'; + const finderVisualClass = + serviceVisualState === 'active' ? 'working' : serviceVisualState === 'settling' ? 'settling' : ''; useEffect(() => { void refresh(); }, []); + useEffect(() => { + return () => { + if (serviceVisualTimerRef.current !== null) { + window.clearTimeout(serviceVisualTimerRef.current); + } + }; + }, []); + + useEffect(() => { + if (!activeLogId) return undefined; + + const timer = window.setTimeout(() => { + setActiveLogId((current) => (current === activeLogId ? null : current)); + }, LOG_VISIBLE_MS); + + return () => window.clearTimeout(timer); + }, [activeLogId]); + async function refresh() { setIsLoading(true); try { - const [status, profiles, targets, detectedComponents] = await Promise.all([ - getStatus(), - getProfiles(), - getTargets(), - getComponents(), - ]); - const activeProfiles = profiles.filter((profile) => profile.enabled); - const mainProfile = profiles.find((profile) => profile.id === MAIN_PROFILE_ID); - const activeProfile = mainProfile ?? activeProfiles[0]; - const activeTarget = targetForUi(targets, status.activeTarget, activeProfile); - const editableProfiles = mainProfile ? [mainProfile] : activeProfiles; - - if (activeTarget) setProxyInput(formatProxy(activeTarget)); - setItems(itemsForProfiles(editableProfiles)); - setLoadedProfiles(profiles); - setProfileId(mainProfile?.id ?? MAIN_PROFILE_ID); - setTargetId(activeTarget?.id ?? activeProfile?.targetId ?? MAIN_TARGET_ID); - - setComponents(detectedComponents); - setGeneratedConfigPath(status.generatedConfigPath); - setNotice(null); + const saved = await getSavedState(); + applySavedState(saved.profiles, saved.targets, saved.generatedConfigPath); } catch { - setNotice({ + showNotice({ kind: 'info', title: 'Режим предпросмотра', text: 'Запусти приложение через Tauri, чтобы увидеть найденный ProxiFyre и применить конфиг.', @@ -98,53 +120,108 @@ export function App() { } finally { setIsLoading(false); } + + void refreshComponents(); } - function addItem() { - const value = normalizeItemValue(newItemValue, newItemType); + async function refreshComponents() { + setIsDetectingComponents(true); + try { + const detectedComponents = await getComponents(); + setComponents(detectedComponents); + } catch (error) { + showNotice({ + kind: 'error', + title: 'ProxiFyre не проверен', + text: errorMessage(error), + }); + } finally { + setIsDetectingComponents(false); + } + } + + function applySavedState(profiles: Profile[], targets: Target[], generatedPath: string) { + const activeProfiles = profiles.filter((profile) => profile.enabled); + const mainProfile = profiles.find((profile) => profile.id === MAIN_PROFILE_ID); + const activeProfile = mainProfile ?? activeProfiles[0]; + const activeTarget = targetForUi(targets, activeProfile); + const editableProfiles = mainProfile ? [mainProfile] : activeProfiles; + + if (activeTarget) setProxyInput(formatProxy(activeTarget)); + setItems(itemsForProfiles(editableProfiles)); + setLoadedProfiles(profiles); + setProfileId(mainProfile?.id ?? MAIN_PROFILE_ID); + setTargetId(activeTarget?.id ?? activeProfile?.targetId ?? MAIN_TARGET_ID); + setGeneratedConfigPath(generatedPath); + } + + function addItem(type: DraftItemType, rawValue: string) { + const value = normalizeItemValue(rawValue, type); if (!value) { - setNotice({ + showNotice({ kind: 'error', title: 'Нечего добавить', - text: newItemType === 'process' ? 'Введи имя процесса.' : 'Введи путь к EXE-файлу.', + text: emptyItemMessage(type), }); - return; + return false; } - if (items.some((item) => item.type === newItemType && sameValue(item.value, value))) { - setNotice({ + if (items.some((item) => item.type === type && sameValue(item.value, value))) { + showNotice({ kind: 'info', title: 'Уже добавлено', text: value, }); - return; + return false; } setItems((current) => [ ...current, { - id: `${newItemType}-${Date.now()}`, - type: newItemType, + id: `${type}-${Date.now()}`, + type, value, }, ]); - setNewItemValue(''); - setNotice(null); + return true; + } + + function addProcess() { + if (addItem('process', processInput)) { + setProcessInput(''); + setIsProcessInputOpen(false); + } } function removeItem(id: string) { setItems((current) => current.filter((item) => item.id !== id)); } + async function pickAndAddItem(type: Extract) { + setPickerAction(type); + try { + const selectedPath = await pickPath(type); + if (selectedPath) { + addItem(type, selectedPath); + } + } catch (error) { + showNotice({ + kind: 'error', + title: type === 'exe' ? 'EXE не выбран' : 'Папка не выбрана', + text: errorMessage(error), + }); + } finally { + setPickerAction(null); + } + } + async function updateConfig() { let parsedProxy: ParsedProxy; try { parsedProxy = parseProxy(proxyInput); - if (!items.length) { - throw new Error('Добавь хотя бы один процесс или EXE-файл.'); - } + if (!items.length) throw new Error('Добавь хотя бы один процесс, EXE-файл или папку.'); } catch (error) { - setNotice({ + showNotice({ kind: 'error', title: 'Проверь данные', text: errorMessage(error), @@ -177,18 +254,16 @@ export function App() { ); const result = await applyProfiles(); - const [status, detectedComponents, profiles] = await Promise.all([ - getStatus(), + const [saved, detectedComponents] = await Promise.all([ + getSavedState(), getComponents(), - getProfiles(), ]); + applySavedState(saved.profiles, saved.targets, result.generatedConfigPath); setComponents(detectedComponents); - setGeneratedConfigPath(status.generatedConfigPath); - setLoadedProfiles(profiles); - setNotice(noticeFromApply(result)); + showNotice(noticeFromApply(result)); } catch (error) { - setNotice({ + showNotice({ kind: 'error', title: 'Конфиг не обновлен', text: errorMessage(error), @@ -202,13 +277,13 @@ export function App() { setIsOpeningConfig(true); try { const openedPath = await openConfigLocation(); - setNotice({ + showNotice({ kind: 'info', title: 'Конфиг открыт', text: openedPath, }); } catch (error) { - setNotice({ + showNotice({ kind: 'error', title: 'Не удалось открыть конфиг', text: errorMessage(error), @@ -218,6 +293,66 @@ export function App() { } } + async function setProxiFyreServiceRunning(shouldRun: boolean) { + const action = shouldRun ? 'start' : 'stop'; + setServiceAction(action); + startServiceVisual(); + try { + await nextFrame(); + const component = shouldRun + ? await startProxiFyreService() + : await stopProxiFyreService(); + + setComponents((current) => upsertComponent(current, component)); + showNotice({ + kind: 'success', + title: shouldRun ? 'Служба запущена' : 'Служба остановлена', + text: proxyfierDetails(component, false), + }); + } catch (error) { + showNotice({ + kind: 'error', + title: shouldRun ? 'Служба не запущена' : 'Служба не остановлена', + text: errorMessage(error), + }); + } finally { + setServiceAction(null); + settleServiceVisual(); + } + } + + function startServiceVisual() { + if (serviceVisualTimerRef.current !== null) { + window.clearTimeout(serviceVisualTimerRef.current); + serviceVisualTimerRef.current = null; + } + + setServiceVisualState('active'); + } + + function settleServiceVisual() { + if (serviceVisualTimerRef.current !== null) { + window.clearTimeout(serviceVisualTimerRef.current); + } + + setServiceVisualState('settling'); + serviceVisualTimerRef.current = window.setTimeout(() => { + setServiceVisualState(null); + serviceVisualTimerRef.current = null; + }, 700); + } + + function showNotice(notice: Notice) { + const entry: LogEntry = { + ...notice, + id: `log-${Date.now()}-${Math.random().toString(36).slice(2)}`, + at: Date.now(), + }; + + setLogEntries((current) => [entry, ...current].slice(0, 40)); + setActiveLogId(entry.id); + } + return (
@@ -226,16 +361,45 @@ export function App() { VPN Proxy

Прокси для приложений

- -
+
+
-
- - setNewItemValue(event.target.value)} - onKeyDown={(event) => { - if (event.key === 'Enter') addItem(); - }} - placeholder={newItemType === 'process' ? 'Discord' : 'C:\\Apps\\app.exe'} - spellCheck={false} - /> - -
+ {isProcessInputOpen ? ( +
+ setProcessInput(event.target.value)} + onKeyDown={(event) => { + if (event.key === 'Enter') addProcess(); + if (event.key === 'Escape') { + setProcessInput(''); + setIsProcessInputOpen(false); + } + }} + placeholder="Discord" + spellCheck={false} + autoFocus + /> + + +
+ ) : ( +
+ + + +
+ )}
- {items.length ? ( + {isLoading ? ( +
+ + +
+ ) : items.length ? ( items.map((item) => (
-
- {item.value} - {item.type === 'process' ? 'процесс' : 'EXE-файл'} +
+ +
+ {item.value} + {itemTypeLabel(item.type)} +
)) ) : ( -
Добавь процесс или путь к EXE-файлу.
+
Добавь процесс, папку или путь к EXE-файлу.
)}
- {notice ? ( -
- {notice.title} - {notice.text} -
- ) : null} -
+ {isLogOpen ? ( +
+ {logEntries.map((entry) => ( +
+ +
+ {entry.title} + {entry.text} +
+
+ ))} +
+ ) : null} + + ) : null}
); } @@ -358,8 +602,7 @@ function parseProxy(rawValue: string): ParsedProxy { return { protocol: 'socks5', host, port }; } -function targetForUi(targets: Target[], activeTarget: Target | undefined, profile: Profile | undefined) { - if (activeTarget) return activeTarget; +function targetForUi(targets: Target[], profile: Profile | undefined) { if (profile) return targets.find((target) => target.id === profile.targetId); return targets.find((target) => target.id === MAIN_TARGET_ID) ?? targets.find((target) => target.kind === 'external'); } @@ -370,7 +613,7 @@ function itemsForProfiles(profiles: Profile[]): DraftItem[] { for (const profile of profiles) { for (const item of profile.items) { - if (item.type !== 'process' && item.type !== 'exe') continue; + if (item.type !== 'process' && item.type !== 'folder' && item.type !== 'exe') continue; const key = `${item.type}:${item.value.trim().toLowerCase()}`; if (seen.has(key)) continue; @@ -395,7 +638,7 @@ function formatProxy(target: Target) { function normalizeItemValue(value: string, type: DraftItemType) { const clean = value.trim().replace(/^"|"$/g, ''); if (!clean) return ''; - if (type === 'exe') return clean; + if (type === 'folder' || type === 'exe') return clean; return clean .split(/[\\/]/) @@ -404,14 +647,58 @@ function normalizeItemValue(value: string, type: DraftItemType) { .trim() ?? ''; } +async function pickPath(type: Extract) { + const selected = await open( + type === 'folder' + ? { + title: 'Выбери папку', + directory: true, + multiple: false, + } + : { + title: 'Выбери EXE-файл', + directory: false, + multiple: false, + filters: [{ name: 'EXE-файлы', extensions: ['exe'] }], + }, + ); + + if (Array.isArray(selected)) return selected[0] ?? null; + return selected; +} + +function nextFrame() { + return new Promise((resolve) => { + window.requestAnimationFrame(() => resolve()); + }); +} + function profileItemInput(item: DraftItem): ProfileItemInput { return { type: item.type, value: item.value, - recursive: false, + recursive: item.type === 'folder', }; } +function emptyItemMessage(type: DraftItemType) { + if (type === 'process') return 'Введи имя процесса.'; + if (type === 'folder') return 'Введи путь к папке.'; + return 'Введи путь к EXE-файлу.'; +} + +function itemTypeLabel(type: DraftItemType) { + if (type === 'process') return 'процесс'; + if (type === 'folder') return 'папка'; + return 'EXE-файл'; +} + +function itemIcon(type: DraftItemType) { + if (type === 'process') return ; + if (type === 'folder') return ; + return ; +} + function profileInputFromProfile(profile: Profile, enabled: boolean) { return { id: profile.id, @@ -427,14 +714,16 @@ function profileInputFromProfile(profile: Profile, enabled: boolean) { }; } -function proxyfierTitle(component: ComponentStatus | undefined) { +function proxyfierTitle(component: ComponentStatus | undefined, checking: boolean) { + if (checking) return 'Проверяю ProxiFyre'; if (!component) return 'ProxiFyre не проверен'; if (component.running) return 'ProxiFyre найден и запущен'; if (component.installed) return 'ProxiFyre найден'; return 'ProxiFyre не найден'; } -function proxyfierDetails(component: ComponentStatus | undefined) { +function proxyfierDetails(component: ComponentStatus | undefined, checking: boolean) { + if (checking) return 'Ищу установленный клиент и состояние службы.'; if (!component) return 'Нажми «Обновить», чтобы проверить компьютер.'; if (component.path) return component.path; return component.problems[0] ?? 'Путь установки не найден.'; @@ -448,10 +737,29 @@ function noticeFromApply(result: ApplyProfilesResponse): Notice { }; } +function upsertComponent(components: ComponentStatus[], component: ComponentStatus) { + const index = components.findIndex((current) => current.id === component.id); + if (index === -1) return [...components, component]; + + return [ + ...components.slice(0, index), + component, + ...components.slice(index + 1), + ]; +} + function sameValue(left: string, right: string) { return left.trim().toLowerCase() === right.trim().toLowerCase(); } +function formatLogTime(timestamp: number) { + return new Date(timestamp).toLocaleTimeString('ru-RU', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); +} + function errorMessage(error: unknown) { if (error instanceof Error) return error.message; if (typeof error === 'string') return error; diff --git a/apps/windows-client/src/styles/app.css b/apps/windows-client/src/styles/app.css index 05b027d..43c81ba 100644 --- a/apps/windows-client/src/styles/app.css +++ b/apps/windows-client/src/styles/app.css @@ -21,8 +21,7 @@ body { } button, -input, -select { +input { font: inherit; } @@ -51,15 +50,15 @@ button:disabled { border-radius: 0; background: #101216; box-shadow: none; - padding: 18px; + padding: 18px 18px 96px; } .simple-header, .finder-card, .section-head, -.add-line, -.app-row, -.notice-line { +.add-toolbar, +.process-add-line, +.app-row { display: flex; align-items: center; justify-content: space-between; @@ -75,7 +74,7 @@ button:disabled { .simple-header small, .simple-field span, -.app-row span, +.app-row-main > div > span, .config-path, .finder-card span { color: #8d99ae; @@ -99,9 +98,11 @@ button:disabled { } .ghost-button, -.add-line button, +.add-toolbar button, +.process-add-line button, .app-row button, -.open-config-button { +.open-config-button, +.service-button { min-height: 36px; border: 1px solid #343b49; border-radius: 4px; @@ -112,30 +113,112 @@ button:disabled { } .ghost-button:hover, -.add-line button:hover, +.add-toolbar button:hover, +.process-add-line button:hover, .app-row button:hover, -.open-config-button:hover { +.open-config-button:hover, +.service-button:hover { background: #2d3543; } .finder-card { - justify-content: flex-start; + position: relative; + isolation: isolate; + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + justify-content: stretch; min-height: 56px; + overflow: hidden; border: 1px solid #2b3342; border-radius: 4px; background: #151923; padding: 12px; } -.finder-card > div, -.app-row > div { +.finder-border-glow { + position: absolute; + z-index: 0; + inset: 0; + overflow: hidden; + border-radius: inherit; + opacity: 0; + pointer-events: none; + transition: opacity 0.22s ease; +} + +.finder-card > :not(.finder-border-glow) { + position: relative; + z-index: 1; +} + +.finder-card.checking .finder-border-glow, +.finder-card.working .finder-border-glow { + opacity: 1; +} + +.finder-card.checking .finder-border-glow { + opacity: 0.78; +} + +.finder-card.settling .finder-border-glow { + opacity: 0; + transition-duration: 0.7s; +} + +.finder-border-glow-segment { + position: absolute; + display: block; + background: #93c5fd; + box-shadow: + 0 0 8px rgba(96, 165, 250, 0.95), + 0 0 16px rgba(34, 197, 94, 0.36); + opacity: 0; +} + +.finder-border-glow-segment.top, +.finder-border-glow-segment.bottom { + width: 108px; + height: 2px; + background: linear-gradient(90deg, transparent, #60a5fa 24%, #bbf7d0 54%, transparent); +} + +.finder-border-glow-segment.right, +.finder-border-glow-segment.left { + width: 2px; + height: 64px; + background: linear-gradient(180deg, transparent, #60a5fa 24%, #bbf7d0 54%, transparent); +} + +.finder-border-glow-segment.top { + top: 0; + animation: finder-border-top 1.6s linear infinite; +} + +.finder-border-glow-segment.right { + right: 0; + animation: finder-border-right 1.6s linear infinite; +} + +.finder-border-glow-segment.bottom { + bottom: 0; + animation: finder-border-bottom 1.6s linear infinite; +} + +.finder-border-glow-segment.left { + left: 0; + animation: finder-border-left 1.6s linear infinite; +} + +.finder-text, +.app-row > div, +.app-row-main > div { min-width: 0; } .finder-card strong, .finder-card span, -.app-row strong, -.app-row span { +.app-row-main strong, +.app-row-main > div > span { display: block; overflow-wrap: anywhere; } @@ -158,6 +241,29 @@ button:disabled { box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.12); } +.finder-card.checking .status-light { + border: 2px solid #3b82f6; + border-top-color: transparent; + background: transparent; + box-shadow: none; + animation: spin 0.75s linear infinite; +} + +.service-actions { + display: flex; + gap: 6px; + align-items: center; +} + +.service-button { + min-width: 102px; + white-space: nowrap; +} + +.service-button.stop { + color: #fecaca; +} + .simple-field { display: grid; gap: 7px; @@ -165,8 +271,7 @@ button:disabled { } .simple-field input, -.add-line input, -.add-line select { +.process-add-line input { min-height: 42px; width: 100%; border: 1px solid #343b49; @@ -178,8 +283,7 @@ button:disabled { } .simple-field input:focus, -.add-line input:focus, -.add-line select:focus { +.process-add-line input:focus { border-color: #3b82f6; box-shadow: 0 0 0 1px #3b82f6; } @@ -202,29 +306,99 @@ button:disabled { font-weight: 700; } -.add-line { - display: grid; - grid-template-columns: 130px minmax(0, 1fr) auto; +.add-toolbar { + justify-content: center; + padding: 4px 0; } -.add-line button { - min-width: 104px; +.add-tile { + display: grid; + place-items: center; + width: 74px; + height: 48px; + border-color: #2b3342; + background: #131720; + color: #dbeafe; + padding: 0; +} + +.add-tile svg { + display: block; +} + +.add-tile:hover { + border-color: #3b82f6; + background: #182033; +} + +.add-tile[aria-pressed="true"] { + border-color: #3b82f6; + background: #1e3a8a; +} + +.tile-loading { + color: #dbeafe; + font-weight: 800; + animation: pulse 1s ease-in-out infinite; +} + +.process-add-line { + display: grid; + grid-template-columns: minmax(0, 1fr) 72px 88px; +} + +.process-add-line button { border-color: #166534; background: #14532d; + font-weight: 700; } -.add-line button:hover { +.process-add-line .process-cancel-button { + border-color: #343b49; + background: #242a35; + color: #cbd5e1; + font-weight: 600; +} + +.process-add-line button:hover { background: #166534; } +.process-add-line .process-cancel-button:hover { + background: #2d3543; +} + .app-list { display: grid; gap: 8px; } +.app-row-main { + display: flex; + align-items: center; + gap: 10px; +} + +.app-row .item-icon { + display: grid; + flex: 0 0 auto; + align-self: center; + place-items: center; + width: 34px; + height: 34px; + border: 1px solid #2b3342; + border-radius: 4px; + background: #0d1016; + color: #dbeafe; + line-height: 0; +} + +.app-row .item-icon svg { + display: block; +} + .app-row, -.empty-state, -.notice-line { +.empty-state { border: 1px solid #2b3342; border-radius: 4px; background: #131720; @@ -240,30 +414,20 @@ button:disabled { min-height: 48px; } -.notice-line { - align-items: flex-start; - justify-content: flex-start; - margin-top: 12px; +.list-skeleton { + display: grid; + gap: 8px; } -.notice-line strong, -.notice-line span { - display: block; -} - -.notice-line.success { - border-color: rgba(34, 197, 94, 0.42); - background: rgba(20, 83, 45, 0.32); -} - -.notice-line.error { - border-color: rgba(239, 68, 68, 0.42); - background: rgba(127, 29, 29, 0.32); -} - -.notice-line.info { - border-color: rgba(59, 130, 246, 0.42); - background: rgba(30, 58, 138, 0.26); +.list-skeleton span { + min-height: 56px; + border: 1px solid #2b3342; + border-radius: 4px; + background: + linear-gradient(90deg, transparent, rgba(148, 163, 184, 0.12), transparent), + #131720; + background-size: 220% 100%; + animation: shimmer 1.15s linear infinite; } .command-row { @@ -299,27 +463,314 @@ button:disabled { overflow-wrap: anywhere; } +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +.log-dock { + position: fixed; + right: 10px; + bottom: 10px; + left: 10px; + z-index: 30; + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; + align-items: center; + min-height: 48px; + border: 1px solid #2b3342; + border-radius: 4px; + background: rgba(19, 23, 32, 0.98); + box-shadow: 0 12px 32px rgba(0, 0, 0, 0.34); + padding: 7px; +} + +.log-dock.error { + border-color: rgba(239, 68, 68, 0.58); +} + +.log-dock.success { + border-color: rgba(34, 197, 94, 0.58); +} + +.log-dock.info { + border-color: rgba(59, 130, 246, 0.58); +} + +.log-current { + display: flex; + min-width: 0; + gap: 10px; + align-items: baseline; + padding: 0 8px; + transition: opacity 180ms ease, transform 180ms ease; +} + +.log-current.hidden { + color: #8d99ae; + opacity: 0.72; +} + +.log-current.visible { + opacity: 1; +} + +.log-current strong, +.log-current span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.log-current strong { + flex: 0 0 auto; +} + +.log-current span { + min-width: 0; +} + +.log-muted { + color: #8d99ae; +} + +.log-toggle { + display: inline-flex; + gap: 8px; + align-items: center; + min-height: 34px; + border: 1px solid #343b49; + border-radius: 4px; + background: #242a35; + color: #eef2ff; + padding: 7px 10px; + cursor: pointer; +} + +.log-toggle:hover { + background: #2d3543; +} + +.log-toggle span { + min-width: 22px; + border-radius: 4px; + background: #1b202b; + color: #dbeafe; + padding: 2px 6px; + text-align: center; + font-size: 12px; + font-weight: 700; +} + +.log-history { + display: grid; + grid-column: 1 / -1; + gap: 6px; + max-height: 230px; + overflow: auto; + border-top: 1px solid #2b3342; + padding-top: 7px; +} + +.log-history-row { + display: grid; + grid-template-columns: 76px minmax(0, 1fr); + gap: 10px; + align-items: start; + border: 1px solid #2b3342; + border-radius: 4px; + background: #0d1016; + padding: 8px; +} + +.log-history-row.error { + border-color: rgba(239, 68, 68, 0.42); +} + +.log-history-row.success { + border-color: rgba(34, 197, 94, 0.36); +} + +.log-history-row.info { + border-color: rgba(59, 130, 246, 0.36); +} + +.log-history-row time { + color: #8d99ae; + font-size: 12px; +} + +.log-history-row strong, +.log-history-row span { + display: block; + overflow-wrap: anywhere; +} + +.log-history-row span { + color: #b6c2d4; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes pulse { + 50% { + opacity: 0.45; + } +} + +@keyframes finder-border-top { + 0% { + left: -116px; + opacity: 0; + } + + 4%, + 23% { + opacity: 1; + } + + 25%, + 100% { + left: calc(100% + 8px); + opacity: 0; + } +} + +@keyframes finder-border-right { + 0%, + 25% { + top: -72px; + opacity: 0; + } + + 29%, + 48% { + opacity: 1; + } + + 50%, + 100% { + top: calc(100% + 8px); + opacity: 0; + } +} + +@keyframes finder-border-bottom { + 0%, + 50% { + right: -116px; + opacity: 0; + } + + 54%, + 73% { + opacity: 1; + } + + 75%, + 100% { + right: calc(100% + 8px); + opacity: 0; + } +} + +@keyframes finder-border-left { + 0%, + 75% { + bottom: -72px; + opacity: 0; + } + + 79%, + 98% { + opacity: 1; + } + + 100% { + bottom: calc(100% + 8px); + opacity: 0; + } +} + +@keyframes shimmer { + from { + background-position: 220% 0; + } + + to { + background-position: -220% 0; + } +} + @media (max-width: 680px) { .simple-shell { padding: 0; } .simple-panel { - padding: 14px; + padding: 14px 14px 100px; } .simple-header, - .app-row, - .notice-line { + .app-row { align-items: stretch; flex-direction: column; } - .add-line { + .add-toolbar { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .add-tile { + width: 100%; + } + + .process-add-line { grid-template-columns: 1fr; } + .finder-card { + grid-template-columns: auto minmax(0, 1fr); + } + + .service-actions { + grid-column: 1 / -1; + } + + .service-button { + flex: 1; + } + .command-row { grid-template-columns: 1fr; } + + .log-dock { + right: 8px; + left: 8px; + grid-template-columns: 1fr; + } + + .log-current { + align-items: flex-start; + flex-direction: column; + gap: 2px; + } + + .log-history-row { + grid-template-columns: 1fr; + } }