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>
65 lines
1.9 KiB
TypeScript
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
|
|
}
|
|
},
|
|
},
|
|
})
|