wraith/src/App.vue
Vantz Stockwell 3638745436
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m3s
feat: tab detach/reattach — pop sessions into separate windows
Right-click any tab → "Detach to Window" opens the session in its
own Tauri window. The tab dims (opacity + italic) while detached.
Close the detached window → session reattaches to the main tab bar.

Architecture:
- DetachedSession.vue: standalone terminal that connects to the same
  backend session (SSH/PTY events keep flowing)
- App.vue detects #/detached-session?sessionId=X hash
- Tab context menu: Detach to Window, Close
- session:reattach event emitted on window close, main window listens
- Monitor bar included in detached SSH windows
- Session.active flag tracks detached state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:37:49 -04:00

59 lines
1.6 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, defineAsyncComponent } from "vue";
import { useAppStore } from "@/stores/app.store";
import UnlockLayout from "@/layouts/UnlockLayout.vue";
const MainLayout = defineAsyncComponent(
() => import("@/layouts/MainLayout.vue")
);
const ToolWindow = defineAsyncComponent(
() => import("@/components/tools/ToolWindow.vue")
);
const DetachedSession = defineAsyncComponent(
() => import("@/components/session/DetachedSession.vue")
);
const app = useAppStore();
// Tool window mode — detected from URL hash: #/tool/network-scanner?sessionId=abc
const isToolMode = ref(false);
const isDetachedMode = ref(false);
const toolName = ref("");
const toolSessionId = ref("");
onMounted(async () => {
const hash = window.location.hash;
if (hash.startsWith("#/tool/")) {
isToolMode.value = true;
const rest = hash.substring(7); // after "#/tool/"
const [name, query] = rest.split("?");
toolName.value = name;
toolSessionId.value = new URLSearchParams(query || "").get("sessionId") || "";
} else if (hash.startsWith("#/detached-session")) {
isDetachedMode.value = true;
} else {
await app.checkVaultState();
}
});
</script>
<template>
<!-- Detached session window mode -->
<DetachedSession v-if="isDetachedMode" />
<!-- Tool popup window mode -->
<ToolWindow v-else-if="isToolMode" :tool="toolName" :session-id="toolSessionId" />
<!-- Normal app mode -->
<div v-else class="app-root">
<UnlockLayout v-if="!app.isUnlocked" />
<MainLayout v-else />
</div>
</template>
<style scoped>
.app-root {
height: 100%;
display: flex;
flex-direction: column;
}
</style>