feat(desktop): add consent-aware repository discovery
This commit is contained in:
Generated
+77
-10
@@ -774,7 +774,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -949,7 +949,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1856,6 +1856,7 @@ dependencies = [
|
||||
"serde_with",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-notification",
|
||||
"tauri-plugin-opener",
|
||||
"tauri-plugin-single-instance",
|
||||
@@ -2045,7 +2046,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2835,6 +2836,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 = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -2874,7 +2899,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2930,7 +2955,7 @@ dependencies = [
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3315,7 +3340,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3659,6 +3684,48 @@ dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-dialog"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940"
|
||||
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-plugin-notification"
|
||||
version = "2.3.3"
|
||||
@@ -3870,7 +3937,7 @@ dependencies = [
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4220,7 +4287,7 @@ dependencies = [
|
||||
"png 0.18.1",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4249,7 +4316,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4627,7 +4694,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -25,6 +25,7 @@ desktop-runtime = [
|
||||
"dep:tauri-plugin-opener",
|
||||
"dep:tauri-plugin-updater",
|
||||
"dep:tauri-plugin-notification",
|
||||
"dep:tauri-plugin-dialog",
|
||||
"dep:tauri-plugin-single-instance",
|
||||
"dep:tauri-runtime",
|
||||
]
|
||||
@@ -49,4 +50,5 @@ tauri-plugin-single-instance = { version = "=2.4.3", optional = true }
|
||||
tauri-plugin-updater = { version = "=2.10.1", optional = true }
|
||||
tauri-plugin-notification = { version = "=2.3.3", optional = true }
|
||||
tauri-plugin-opener = { version = "=2.5.4", optional = true }
|
||||
tauri-plugin-dialog = { version = "=2.7.2", optional = true }
|
||||
url = "2"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSDesktopFolderUsageDescription</key>
|
||||
<string>Kandev needs access to folders you choose to discover local repositories.</string>
|
||||
<key>NSDocumentsFolderUsageDescription</key>
|
||||
<string>Kandev needs access to folders you choose to discover local repositories.</string>
|
||||
<key>NSDownloadsFolderUsageDescription</key>
|
||||
<string>Kandev needs access to folders you choose to discover local repositories.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -8,6 +8,7 @@ fn main() {
|
||||
"get_native_notification_permission",
|
||||
"request_native_notification_permission",
|
||||
"open_external_url",
|
||||
"pick_directory",
|
||||
]);
|
||||
tauri_build::try_build(tauri_build::Attributes::new().app_manifest(manifest))
|
||||
.expect("failed to build Tauri desktop application");
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"allow-show-native-notification",
|
||||
"allow-get-native-notification-permission",
|
||||
"allow-request-native-notification-permission",
|
||||
"allow-open-external-url"
|
||||
"allow-open-external-url",
|
||||
"allow-pick-directory"
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"default":{"identifier":"default","description":"Desktop bridge; privileged commands verify the exact owned backend origin","remote":{"urls":["http://127.0.0.1:*"]},"local":false,"windows":["main"],"permissions":["core:event:allow-listen","core:event:allow-unlisten","allow-get-update-state","allow-check-for-updates","allow-install-update","allow-show-native-notification","allow-get-native-notification-permission","allow-request-native-notification-permission","allow-open-external-url"]}}
|
||||
{"default":{"identifier":"default","description":"Desktop bridge; privileged commands verify the exact owned backend origin","remote":{"urls":["http://127.0.0.1:*"]},"local":false,"windows":["main"],"permissions":["core:event:allow-listen","core:event:allow-unlisten","allow-get-update-state","allow-check-for-updates","allow-install-update","allow-show-native-notification","allow-get-native-notification-permission","allow-request-native-notification-permission","allow-open-external-url","allow-pick-directory"]}}
|
||||
@@ -374,6 +374,12 @@
|
||||
"const": "allow-open-external-url",
|
||||
"markdownDescription": "Enables the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the pick_directory command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-pick-directory",
|
||||
"markdownDescription": "Enables the pick_directory command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the request_native_notification_permission command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -416,6 +422,12 @@
|
||||
"const": "deny-open-external-url",
|
||||
"markdownDescription": "Denies the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the pick_directory command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-pick-directory",
|
||||
"markdownDescription": "Denies the pick_directory command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the request_native_notification_permission command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2444,6 +2456,72 @@
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"description": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`",
|
||||
"type": "string",
|
||||
|
||||
@@ -374,6 +374,12 @@
|
||||
"const": "allow-open-external-url",
|
||||
"markdownDescription": "Enables the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the pick_directory command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "allow-pick-directory",
|
||||
"markdownDescription": "Enables the pick_directory command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Enables the request_native_notification_permission command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -416,6 +422,12 @@
|
||||
"const": "deny-open-external-url",
|
||||
"markdownDescription": "Denies the open_external_url command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the pick_directory command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"const": "deny-pick-directory",
|
||||
"markdownDescription": "Denies the pick_directory command without any pre-configured scope."
|
||||
},
|
||||
{
|
||||
"description": "Denies the request_native_notification_permission command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
@@ -2444,6 +2456,72 @@
|
||||
"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."
|
||||
},
|
||||
{
|
||||
"description": "This permission set configures which\nnotification features are by default exposed.\n\n#### Granted Permissions\n\nIt allows all notification related features.\n\n\n#### This default permission set includes:\n\n- `allow-is-permission-granted`\n- `allow-request-permission`\n- `allow-notify`\n- `allow-register-action-types`\n- `allow-register-listener`\n- `allow-cancel`\n- `allow-get-pending`\n- `allow-remove-active`\n- `allow-get-active`\n- `allow-check-permissions`\n- `allow-show`\n- `allow-batch`\n- `allow-list-channels`\n- `allow-delete-channel`\n- `allow-create-channel`\n- `allow-permission-state`",
|
||||
"type": "string",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[[permission]]
|
||||
identifier = "allow-pick-directory"
|
||||
description = "Enables the Kandev-owned directory picker command without exposing generic dialog commands."
|
||||
commands.allow = ["pick_directory"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-pick-directory"
|
||||
description = "Denies the Kandev-owned directory picker command."
|
||||
commands.deny = ["pick_directory"]
|
||||
@@ -0,0 +1,11 @@
|
||||
# Automatically generated - DO NOT EDIT!
|
||||
|
||||
[[permission]]
|
||||
identifier = "allow-pick-directory"
|
||||
description = "Enables the pick_directory command without any pre-configured scope."
|
||||
commands.allow = ["pick_directory"]
|
||||
|
||||
[[permission]]
|
||||
identifier = "deny-pick-directory"
|
||||
description = "Denies the pick_directory command without any pre-configured scope."
|
||||
commands.deny = ["pick_directory"]
|
||||
@@ -24,6 +24,7 @@ const DEFAULT_DESKTOP_PORT: u16 = 38430;
|
||||
const DESKTOP_PORT_ENV: &str = "KANDEV_DESKTOP_PORT";
|
||||
const DESKTOP_HEALTH_TOKEN_ENV: &str = "KANDEV_DESKTOP_HEALTH_TOKEN";
|
||||
const DESKTOP_NATIVE_NOTIFICATIONS_ENV: &str = "KANDEV_DESKTOP_NATIVE_NOTIFICATIONS";
|
||||
const DESKTOP_RUNTIME_ENV: &str = "KANDEV_DESKTOP_RUNTIME";
|
||||
const LAUNCHER_PARENT_PID_ENV: &str = "KANDEV_LAUNCHER_PARENT_PID";
|
||||
const DESKTOP_HEALTH_TOKEN_HEADER: &str = "x-kandev-desktop-health-token";
|
||||
const STARTUP_OUTPUT_LIMIT: usize = 12 * 1024;
|
||||
@@ -369,8 +370,9 @@ pub fn desktop_environment(
|
||||
) -> BTreeMap<OsString, OsString> {
|
||||
let path = normalized_path(env.get(OsStr::new("PATH")), home_dir);
|
||||
env.retain(|key, _| {
|
||||
!key.to_string_lossy()
|
||||
.eq_ignore_ascii_case(DESKTOP_NATIVE_NOTIFICATIONS_ENV)
|
||||
let key = key.to_string_lossy();
|
||||
!key.eq_ignore_ascii_case(DESKTOP_NATIVE_NOTIFICATIONS_ENV)
|
||||
&& !key.eq_ignore_ascii_case(DESKTOP_RUNTIME_ENV)
|
||||
});
|
||||
env.insert(
|
||||
OsString::from("KANDEV_SERVER_HOST"),
|
||||
@@ -384,6 +386,7 @@ pub fn desktop_environment(
|
||||
OsString::from(DESKTOP_NATIVE_NOTIFICATIONS_ENV),
|
||||
OsString::from("true"),
|
||||
);
|
||||
env.insert(OsString::from(DESKTOP_RUNTIME_ENV), OsString::from("true"));
|
||||
env.insert(OsString::from("PATH"), path);
|
||||
env
|
||||
}
|
||||
@@ -730,6 +733,10 @@ fn current_home_dir() -> Option<PathBuf> {
|
||||
.map(PathBuf::from)
|
||||
}
|
||||
|
||||
pub(crate) fn picker_home_dir() -> Option<PathBuf> {
|
||||
current_home_dir()
|
||||
}
|
||||
|
||||
fn executable_name(name: &str) -> OsString {
|
||||
if cfg!(windows) {
|
||||
OsString::from(format!("{name}.exe"))
|
||||
@@ -870,6 +877,10 @@ mod tests {
|
||||
.get(OsStr::new("KANDEV_DESKTOP_NATIVE_NOTIFICATIONS")),
|
||||
Some(&OsString::from("true"))
|
||||
);
|
||||
assert_eq!(
|
||||
spec.env.get(OsStr::new("KANDEV_DESKTOP_RUNTIME")),
|
||||
Some(&OsString::from("true"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
use serde::Serialize;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// The result of the deliberately narrow native folder-selection boundary.
|
||||
/// The command never accepts a path from the WebView. The selected path is
|
||||
/// returned only after the user chooses it in the operating-system picker.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
#[serde(tag = "status", rename_all = "camelCase")]
|
||||
pub enum FolderPickerOutcome {
|
||||
Selected { path: String },
|
||||
Cancelled,
|
||||
Failed { message: String },
|
||||
}
|
||||
|
||||
fn outcome_from_path(path: Option<Result<PathBuf, String>>) -> FolderPickerOutcome {
|
||||
match path {
|
||||
Some(Ok(path)) => FolderPickerOutcome::Selected {
|
||||
path: path.to_string_lossy().into_owned(),
|
||||
},
|
||||
Some(Err(message)) => FolderPickerOutcome::Failed { message },
|
||||
None => FolderPickerOutcome::Cancelled,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop-runtime")]
|
||||
#[tauri::command]
|
||||
pub fn pick_directory(
|
||||
app: tauri::AppHandle,
|
||||
backend: tauri::State<'_, crate::backend::BackendState>,
|
||||
webview: tauri::WebviewWindow,
|
||||
) -> Result<FolderPickerOutcome, String> {
|
||||
use tauri_plugin_dialog::{DialogExt, FilePath};
|
||||
|
||||
backend.require_owned_origin(&webview)?;
|
||||
let home = crate::backend::picker_home_dir()
|
||||
.ok_or_else(|| "could not determine the desktop user's home directory".to_string())?;
|
||||
let picked = app
|
||||
.dialog()
|
||||
.file()
|
||||
.set_directory(home)
|
||||
.set_parent(&webview)
|
||||
.blocking_pick_folder();
|
||||
let result = picked.map(|path: FilePath| path.into_path().map_err(|err| err.to_string()));
|
||||
Ok(outcome_from_path(result))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn maps_a_selected_directory() {
|
||||
assert_eq!(
|
||||
outcome_from_path(Some(Ok(PathBuf::from("/Users/example/Code")))),
|
||||
FolderPickerOutcome::Selected {
|
||||
path: "/Users/example/Code".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_cancellation_without_a_path() {
|
||||
assert_eq!(outcome_from_path(None), FolderPickerOutcome::Cancelled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maps_picker_failures_without_exposing_a_path_argument() {
|
||||
assert_eq!(
|
||||
outcome_from_path(Some(Err("picker unavailable".to_string()))),
|
||||
FolderPickerOutcome::Failed {
|
||||
message: "picker unavailable".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod backend;
|
||||
pub mod external_links;
|
||||
pub mod folder_picker;
|
||||
pub mod native_notifications;
|
||||
pub mod shell;
|
||||
pub mod updater;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use kandev_desktop::{
|
||||
backend, external_links,
|
||||
backend, external_links, folder_picker,
|
||||
native_notifications::{self, NativeNotificationState},
|
||||
shell::{self, MenuAction, ZoomState},
|
||||
updater::{self, UpdaterState},
|
||||
@@ -22,6 +22,7 @@ fn main() {
|
||||
let app = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||
.plugin(tauri_plugin_notification::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(
|
||||
tauri_plugin_opener::Builder::new()
|
||||
.open_js_links_on_click(false)
|
||||
@@ -42,6 +43,7 @@ fn main() {
|
||||
native_notifications::get_native_notification_permission,
|
||||
native_notifications::request_native_notification_permission,
|
||||
external_links::open_external_url,
|
||||
folder_picker::pick_directory,
|
||||
])
|
||||
.menu(build_menu)
|
||||
.on_menu_event(handle_menu_event)
|
||||
|
||||
@@ -58,6 +58,9 @@
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "https://timestamp.digicert.com",
|
||||
"signCommand": "powershell -NoProfile -ExecutionPolicy Bypass -File ./windows-sign.ps1 %1"
|
||||
},
|
||||
"macOS": {
|
||||
"infoPlist": "Info.plist"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user