Root cause: TerminalInstance.onMounted() called sessions.removeSession() on the pending session, dropping sessions.length to 0. SessionContainer's v-if="hasSessions" went false, unmounting the entire terminal UI before the WebSocket could establish and add the real session. Fix: Added replaceSession() to session store. TerminalInstance no longer removes the pending session — instead passes its ID to connectToHost(), which swaps it in-place when the backend responds with the real session ID. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
47 lines
1.3 KiB
Vue
47 lines
1.3 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
|
import { useTerminal } from '~/composables/useTerminal'
|
|
import { useSessionStore } from '~/stores/session.store'
|
|
|
|
const props = defineProps<{
|
|
sessionId: string // may be a pending-XXX id initially
|
|
hostId: number
|
|
hostName: string
|
|
color: string | null
|
|
}>()
|
|
|
|
const termContainer = ref<HTMLElement | null>(null)
|
|
const sessions = useSessionStore()
|
|
const { createTerminal, connectToHost, disconnect } = useTerminal()
|
|
|
|
let termInstance: ReturnType<typeof createTerminal> | null = null
|
|
// Track the real backend sessionId once connected (replaces pending-XXX)
|
|
let realSessionId: string | null = null
|
|
|
|
onMounted(() => {
|
|
if (!termContainer.value) return
|
|
|
|
termInstance = createTerminal(termContainer.value)
|
|
const { term, fitAddon } = termInstance
|
|
|
|
// Connect — useTerminal will replace the pending session with the real backend sessionId
|
|
connectToHost(props.hostId, props.hostName, 'ssh', props.color, props.sessionId, term, fitAddon)
|
|
})
|
|
|
|
onBeforeUnmount(() => {
|
|
if (termInstance) {
|
|
termInstance.resizeObserver.disconnect()
|
|
termInstance.term.dispose()
|
|
}
|
|
if (realSessionId) {
|
|
disconnect(realSessionId)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="w-full h-full bg-[#0a0a0f]">
|
|
<div ref="termContainer" class="w-full h-full" />
|
|
</div>
|
|
</template>
|