wraith/frontend/stores/session.store.ts
Vantz Stockwell e1be07f34c feat: session tabs with home nav, popup Monaco editor, drag-and-drop upload
Multi-session tabs + home navigation:
- Tab bar with Home button persists above sessions
- Clicking Home shows the underlying page (hosts, vault, etc.)
- Clicking a session tab switches back to that session
- Header nav links also trigger home view
- Sessions stay alive in background when viewing home

Monaco editor in popup window:
- Opening a file in SFTP launches a detached popup with Monaco
- Full syntax highlighting, minimap, Ctrl+S save
- File tree stays visible while editing
- Toolbar with save/close buttons and dirty indicator

Drag-and-drop upload:
- Drop files anywhere on the SFTP sidebar to upload
- Visual overlay with dashed border on drag-over
- Supports multiple files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 13:20:40 -04:00

65 lines
1.9 KiB
TypeScript

import { defineStore } from 'pinia'
interface Session {
key: string // stable Vue key — never changes after creation
id: string // uuid from backend (starts as pending-XXX, replaced with real UUID)
hostId: number
hostName: string
protocol: 'ssh' | 'rdp'
color: string | null
active: boolean
cwd?: string // current working directory (SSH only, set via OSC 7 shell integration)
}
export const useSessionStore = defineStore('sessions', {
state: () => ({
sessions: [] as Session[],
activeSessionId: null as string | null,
showHome: false,
}),
getters: {
activeSession: (state) => state.sessions.find(s => s.id === state.activeSessionId),
hasSessions: (state) => state.sessions.length > 0,
},
actions: {
addSession(session: Session) {
this.sessions.push(session)
this.activeSessionId = session.id
this.showHome = false
},
removeSession(id: string) {
this.sessions = this.sessions.filter(s => s.id !== id)
if (this.activeSessionId === id) {
this.activeSessionId = this.sessions.length ? this.sessions[this.sessions.length - 1].id : null
}
if (!this.sessions.length) {
this.showHome = false
}
},
replaceSession(oldId: string, newSession: Session) {
const idx = this.sessions.findIndex(s => s.id === oldId)
if (idx !== -1) {
// Preserve the stable key so Vue doesn't remount the component
newSession.key = this.sessions[idx].key
this.sessions[idx] = newSession
} else {
this.sessions.push(newSession)
}
this.activeSessionId = newSession.id
},
setActive(id: string) {
this.activeSessionId = id
this.showHome = false
},
goHome() {
this.showHome = true
},
updateCwd(sessionId: string, cwd: string) {
const session = this.sessions.find(s => s.id === sessionId)
if (session) {
session.cwd = cwd
}
},
},
})