feat(web): wire terminal panel to workspace shell ws
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,12 @@ import { FitAddon } from "@xterm/addon-fit";
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { useProcessStatus, useProcessWebSocket } from "@/lib/api/process";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
useShellStart,
|
||||
useShellStatus,
|
||||
useShellWebSocket,
|
||||
} from "@/lib/api/process";
|
||||
|
||||
interface TerminalPanelProps {
|
||||
workspaceId: string | null;
|
||||
@@ -16,12 +21,10 @@ export function TerminalPanel({ workspaceId }: TerminalPanelProps) {
|
||||
const isDeadRef = useRef(false);
|
||||
const [failed, setFailed] = useState(false);
|
||||
const [isDead, setIsDead] = useState(false);
|
||||
const { data: processStatus } = useProcessStatus(workspaceId);
|
||||
const processRunning = processStatus?.running === true;
|
||||
const { status, send, onData } = useProcessWebSocket(
|
||||
workspaceId,
|
||||
processRunning,
|
||||
);
|
||||
const { data: shellStatus } = useShellStatus(workspaceId);
|
||||
const shellRunning = shellStatus?.running === true;
|
||||
const { status, send, onData } = useShellWebSocket(workspaceId, shellRunning);
|
||||
const startShell = useShellStart();
|
||||
|
||||
// Initialize xterm once and keep it alive across WS status changes.
|
||||
useEffect(() => {
|
||||
@@ -146,22 +149,33 @@ export function TerminalPanel({ workspaceId }: TerminalPanelProps) {
|
||||
}
|
||||
|
||||
const statusHint = isDead
|
||||
? "process exited — use the toolbar to start"
|
||||
? "shell exited"
|
||||
: status === "error"
|
||||
? "terminal disconnected"
|
||||
: status === "connecting"
|
||||
? "connecting…"
|
||||
: null;
|
||||
|
||||
const hint = processRunning
|
||||
const hint = shellRunning
|
||||
? statusHint
|
||||
: "process not running — start it from the toolbar";
|
||||
: "shell not running - start it to use the terminal";
|
||||
|
||||
return (
|
||||
<section className="flex h-full w-full flex-col overflow-hidden bg-[#171717]">
|
||||
{hint && (
|
||||
<div className="flex h-6 shrink-0 items-center px-2 text-[11px] text-muted-foreground">
|
||||
<div className="flex h-6 shrink-0 items-center gap-2 px-2 text-[11px] text-muted-foreground">
|
||||
{hint}
|
||||
{!shellRunning && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-5 px-1.5 text-[11px]"
|
||||
onClick={() => workspaceId && startShell.mutate(workspaceId)}
|
||||
disabled={!workspaceId || startShell.isPending}
|
||||
>
|
||||
{startShell.isPending ? "starting…" : "Start shell"}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div ref={containerRef} className="min-h-0 flex-1 p-2" />
|
||||
|
||||
Reference in New Issue
Block a user