Compare commits
No commits in common. "main" and "v1.13.1" have entirely different histories.
@ -2,12 +2,9 @@ use tauri::AppHandle;
|
|||||||
use tauri::WebviewWindowBuilder;
|
use tauri::WebviewWindowBuilder;
|
||||||
|
|
||||||
/// Open a child window from the Rust side using WebviewWindowBuilder.
|
/// Open a child window from the Rust side using WebviewWindowBuilder.
|
||||||
///
|
/// This is more reliable than JS-side WebviewWindow on macOS WKWebView.
|
||||||
/// The `url` parameter supports hash fragments (e.g. "index.html#/tool/ping?sessionId=abc").
|
|
||||||
/// WebviewUrl::App takes a PathBuf and cannot handle hash/query — so we load plain
|
|
||||||
/// index.html and set the hash via JS after the window is created.
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn open_child_window(
|
pub async fn open_child_window(
|
||||||
app_handle: AppHandle,
|
app_handle: AppHandle,
|
||||||
label: String,
|
label: String,
|
||||||
title: String,
|
title: String,
|
||||||
@ -15,26 +12,13 @@ pub fn open_child_window(
|
|||||||
width: f64,
|
width: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
// Split "index.html#/tool/ping?sessionId=abc" into path and fragment
|
let webview_url = tauri::WebviewUrl::App(url.into());
|
||||||
let (path, hash) = match url.split_once('#') {
|
WebviewWindowBuilder::new(&app_handle, &label, webview_url)
|
||||||
Some((p, h)) => (p.to_string(), Some(format!("#{}", h))),
|
|
||||||
None => (url.clone(), None),
|
|
||||||
};
|
|
||||||
|
|
||||||
let webview_url = tauri::WebviewUrl::App(path.into());
|
|
||||||
let window = WebviewWindowBuilder::new(&app_handle, &label, webview_url)
|
|
||||||
.title(&title)
|
.title(&title)
|
||||||
.inner_size(width, height)
|
.inner_size(width, height)
|
||||||
.resizable(true)
|
.resizable(true)
|
||||||
.center()
|
.center()
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| format!("Failed to create window '{}': {}", label, e))?;
|
.map_err(|e| format!("Failed to create window '{}': {}", label, e))?;
|
||||||
|
|
||||||
// Set the hash fragment after the window loads — this triggers App.vue's
|
|
||||||
// onMounted hash detection to render the correct tool/detached component.
|
|
||||||
if let Some(hash) = hash {
|
|
||||||
let _ = window.eval(&format!("window.location.hash = '{}';", hash));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/App.vue
24
src/App.vue
@ -16,6 +16,7 @@ const DetachedSession = defineAsyncComponent({
|
|||||||
const app = useAppStore();
|
const app = useAppStore();
|
||||||
const appError = ref<string | null>(null);
|
const appError = ref<string | null>(null);
|
||||||
|
|
||||||
|
// Tool window mode — detected from URL hash: #/tool/network-scanner?sessionId=abc
|
||||||
const isToolMode = ref(false);
|
const isToolMode = ref(false);
|
||||||
const isDetachedMode = ref(false);
|
const isDetachedMode = ref(false);
|
||||||
const toolName = ref("");
|
const toolName = ref("");
|
||||||
@ -27,39 +28,32 @@ onErrorCaptured((err) => {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Parse hash and set mode flags. Called on mount and on hashchange. */
|
onMounted(async () => {
|
||||||
function applyHash(hash: string): void {
|
const hash = window.location.hash;
|
||||||
if (hash.startsWith("#/tool/")) {
|
if (hash.startsWith("#/tool/")) {
|
||||||
isToolMode.value = true;
|
isToolMode.value = true;
|
||||||
const rest = hash.substring(7);
|
const rest = hash.substring(7); // after "#/tool/"
|
||||||
const [name, query] = rest.split("?");
|
const [name, query] = rest.split("?");
|
||||||
toolName.value = name;
|
toolName.value = name;
|
||||||
toolSessionId.value = new URLSearchParams(query || "").get("sessionId") || "";
|
toolSessionId.value = new URLSearchParams(query || "").get("sessionId") || "";
|
||||||
} else if (hash.startsWith("#/detached-session")) {
|
} else if (hash.startsWith("#/detached-session")) {
|
||||||
isDetachedMode.value = true;
|
isDetachedMode.value = true;
|
||||||
}
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
// Check hash at load time (present if JS-side WebviewWindow set it in the URL)
|
|
||||||
applyHash(window.location.hash);
|
|
||||||
|
|
||||||
// Also listen for hash changes (Rust-side window sets hash via eval after load)
|
|
||||||
window.addEventListener("hashchange", () => applyHash(window.location.hash));
|
|
||||||
|
|
||||||
// Only init vault for the main app window (no hash)
|
|
||||||
if (!isToolMode.value && !isDetachedMode.value) {
|
|
||||||
await app.checkVaultState();
|
await app.checkVaultState();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<!-- Error display for debugging -->
|
||||||
<div v-if="appError" class="fixed inset-0 z-50 flex items-center justify-center bg-[#0d1117] text-red-400 p-8 text-sm font-mono whitespace-pre-wrap">
|
<div v-if="appError" class="fixed inset-0 z-50 flex items-center justify-center bg-[#0d1117] text-red-400 p-8 text-sm font-mono whitespace-pre-wrap">
|
||||||
{{ appError }}
|
{{ appError }}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Detached session window mode -->
|
||||||
<DetachedSession v-else-if="isDetachedMode" />
|
<DetachedSession v-else-if="isDetachedMode" />
|
||||||
|
<!-- Tool popup window mode -->
|
||||||
<ToolWindow v-else-if="isToolMode" :tool="toolName" :session-id="toolSessionId" />
|
<ToolWindow v-else-if="isToolMode" :tool="toolName" :session-id="toolSessionId" />
|
||||||
|
<!-- Normal app mode -->
|
||||||
<div v-else class="app-root">
|
<div v-else class="app-root">
|
||||||
<UnlockLayout v-if="!app.isUnlocked" />
|
<UnlockLayout v-if="!app.isUnlocked" />
|
||||||
<MainLayout v-else />
|
<MainLayout v-else />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user