import { useEffect, useRef, useImperativeHandle, forwardRef } from 'react'; import { STORAGE } from '../lib/storage-keys'; import { WebTerminal } from '../lib/terminal/WebTerminal'; import type { TerminalConfig } from '../lib/terminal/terminal-config'; interface TerminalViewProps { sessionId: string; adapter?: string; style?: React.CSSProperties; } export interface TerminalViewHandle { closeKeyboard(): void; } function buildTerminalWsUrl(sessionId: string, adapter?: string): string { const proto = location.protocol === 'https:' ? 'wss' : 'ws'; const token = localStorage.getItem(STORAGE.TOKEN) ?? ''; const adapterParam = adapter ? `&adapter=${encodeURIComponent(adapter)}` : ''; return `${proto}://${location.host}/terminal/${encodeURIComponent(sessionId)}?token=${encodeURIComponent(token)}${adapterParam}`; } const TERMINAL_CONFIG: TerminalConfig = { fontSize: 14, }; export const TerminalView = forwardRef( function TerminalView({ sessionId, adapter, style }, ref) { const containerRef = useRef(null); const termRef = useRef(null); useImperativeHandle(ref, () => ({ closeKeyboard() { termRef.current?.closeKeyboard(); }, })); useEffect(() => { const el = containerRef.current; if (!el) return; const wsUrl = buildTerminalWsUrl(sessionId, adapter); let cancelled = false; WebTerminal.create(el, wsUrl, TERMINAL_CONFIG).then((t) => { if (cancelled) { t.dispose(); return; } termRef.current = t; }).catch((err) => { console.error('[TerminalView] Failed to create terminal:', err); }); return () => { cancelled = true; termRef.current?.dispose(); termRef.current = null; }; }, [sessionId, adapter]); return (
); } );