support open browse path

This commit is contained in:
Julian Freeman
2026-04-16 14:58:40 -04:00
parent a8ad89074f
commit 3fa6a91717
9 changed files with 159 additions and 12 deletions

View File

@@ -10,15 +10,16 @@
"tauri": "tauri"
},
"dependencies": {
"vue": "^3.5.13",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-opener": "^2"
"@tauri-apps/plugin-dialog": "^2.7.0",
"@tauri-apps/plugin-opener": "^2",
"vue": "^3.5.13"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
"@vitejs/plugin-vue": "^5.2.1",
"typescript": "~5.6.2",
"vite": "^6.0.3",
"vue-tsc": "^2.1.10",
"@tauri-apps/cli": "^2"
"vue-tsc": "^2.1.10"
}
}

10
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@tauri-apps/api':
specifier: ^2
version: 2.10.1
'@tauri-apps/plugin-dialog':
specifier: ^2.7.0
version: 2.7.0
'@tauri-apps/plugin-opener':
specifier: ^2
version: 2.5.3
@@ -429,6 +432,9 @@ packages:
engines: {node: '>= 10'}
hasBin: true
'@tauri-apps/plugin-dialog@2.7.0':
resolution: {integrity: sha512-4nS/hfGMGCXiAS3LtVjH9AgsSAPJeG/7R+q8agTFqytjnMa4Zq95Bq8WzVDkckpanX+yyRHXnRtrKXkANKDHvw==}
'@tauri-apps/plugin-opener@2.5.3':
resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==}
@@ -859,6 +865,10 @@ snapshots:
'@tauri-apps/cli-win32-ia32-msvc': 2.10.1
'@tauri-apps/cli-win32-x64-msvc': 2.10.1
'@tauri-apps/plugin-dialog@2.7.0':
dependencies:
'@tauri-apps/api': 2.10.1
'@tauri-apps/plugin-opener@2.5.3':
dependencies:
'@tauri-apps/api': 2.10.1

68
src-tauri/Cargo.lock generated
View File

@@ -453,6 +453,7 @@ dependencies = [
"serde_json",
"tauri",
"tauri-build",
"tauri-plugin-dialog",
"tauri-plugin-opener",
]
@@ -2276,6 +2277,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
"bitflags 2.11.1",
"block2",
"libc",
"objc2",
"objc2-core-foundation",
]
@@ -3007,6 +3009,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.2"
@@ -3749,6 +3775,48 @@ dependencies = [
"walkdir",
]
[[package]]
name = "tauri-plugin-dialog"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1fa4150c95ae391946cc8b8f905ab14797427caba3a8a2f79628e956da91809"
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.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36e1ec28b79f3d0683f4507e1615c36292c0ea6716668770d4396b9b39871ed8"
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 0.9.12+spec-1.1.0",
"url",
]
[[package]]
name = "tauri-plugin-opener"
version = "2.5.3"

View File

@@ -23,4 +23,5 @@ tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
base64 = "0.22"
tauri-plugin-dialog = "2.7.0"

View File

@@ -5,6 +5,7 @@
"windows": ["main"],
"permissions": [
"core:default",
"dialog:default",
"opener:default"
]
}

View File

@@ -8,6 +8,7 @@ mod utils;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![
commands::scan_browsers,

View File

@@ -27,6 +27,8 @@ const {
openProfileError,
openBrowserProfile,
page,
pickExecutablePath,
pickUserDataPath,
profileSortKey,
refreshAll,
savingConfig,
@@ -115,17 +117,35 @@ const {
</label>
<label class="field-group">
<span>Executable Path</span>
<input
v-model="createConfigForm.executablePath"
placeholder="C:\Program Files\...\chrome.exe"
/>
<div class="path-input-row">
<input
v-model="createConfigForm.executablePath"
placeholder="C:\Program Files\...\chrome.exe"
/>
<button
class="secondary-button"
type="button"
@click="pickExecutablePath"
>
Browse File
</button>
</div>
</label>
<label class="field-group field-span">
<span>User Data Path</span>
<input
v-model="createConfigForm.userDataPath"
placeholder="C:\Users\...\User Data"
/>
<div class="path-input-row">
<input
v-model="createConfigForm.userDataPath"
placeholder="C:\Users\...\User Data"
/>
<button
class="secondary-button"
type="button"
@click="pickUserDataPath"
>
Browse Folder
</button>
</div>
</label>
</div>
<div class="config-form-actions">

View File

@@ -1,5 +1,6 @@
import { computed, onMounted, ref, watch } from "vue";
import { invoke } from "@tauri-apps/api/core";
import { open } from "@tauri-apps/plugin-dialog";
import { sortBookmarks, sortExtensions, sortProfiles } from "./sort";
import type {
@@ -179,6 +180,34 @@ export function useBrowserAssistant() {
}
}
async function pickExecutablePath() {
const selected = await open({
multiple: false,
directory: false,
filters: [
{
name: "Executable",
extensions: ["exe"],
},
],
});
if (typeof selected === "string") {
createConfigForm.value.executablePath = selected;
}
}
async function pickUserDataPath() {
const selected = await open({
multiple: false,
directory: true,
});
if (typeof selected === "string") {
createConfigForm.value.userDataPath = selected;
}
}
function isDeletingConfig(configId: string) {
return deletingConfigId.value === configId;
}
@@ -289,6 +318,8 @@ export function useBrowserAssistant() {
openProfileError,
openBrowserProfile,
page,
pickExecutablePath,
pickUserDataPath,
profileSortKey,
refreshAll,
savingConfig,

View File

@@ -357,6 +357,12 @@ button {
gap: 6px;
}
.path-input-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
}
.field-group span,
.config-label {
color: var(--muted);
@@ -390,6 +396,7 @@ button {
}
.primary-button,
.secondary-button,
.danger-button {
padding: 9px 14px;
border-radius: 12px;
@@ -403,6 +410,12 @@ button {
color: #fff;
}
.secondary-button {
border: 1px solid rgba(148, 163, 184, 0.24);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(241, 245, 249, 0.92));
color: var(--text);
}
.danger-button {
border: 1px solid rgba(239, 68, 68, 0.18);
background: rgba(254, 242, 242, 0.96);
@@ -410,6 +423,7 @@ button {
}
.primary-button:disabled,
.secondary-button:disabled,
.danger-button:disabled {
cursor: default;
opacity: 0.72;