// React port of ../../killDialog.ts: the two kill prompts (#81, #160). The // daemon refuses an unforced kill over a worktree holding unsaved work; the // same component in `force` mode is the override that follows that refusal. import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { formatInTheWay, type InTheWay } from "../../types.js"; export interface KillDialogProps { /** Session name, as the sidebar shows it. */ name: string; /** What the card last saw in the way, when anything was. */ blockers: InTheWay | null; /** Set once the daemon has refused an unforced kill: this pass forces it, * and `reason` carries the daemon's refusal message. */ force?: boolean; /** Message from the daemon's refusal, shown when there are no blockers to * spell out. */ reason?: string; /** Run the kill (or the forced kill). A rejection is rendered inline, and * the dialog stays open so the press can be retried. */ onConfirm(): Promise; onCancel(): void; } export function KillDialog(props: KillDialogProps) { const { name, blockers, force, reason, onConfirm, onCancel } = props; const confirmRef = useRef(null); const [pending, setPending] = useState(false); const [error, setError] = useState(null); // The acting button takes the focus in both modes: the operator already // asked for the kill, so Enter confirms it. useEffect(() => confirmRef.current?.focus(), []); const handleConfirm = () => { setPending(true); setError(null); void onConfirm().catch((e: unknown) => { setPending(false); setError(`Failed to kill: ${(e as Error).message}`); }); }; const body = blockers ? force ? `Its worktree still has ${formatInTheWay(blockers)}. Forcing the kill removes the session and leaves the worktree on disk.` : `Its worktree still has ${formatInTheWay(blockers)}. The kill will be refused unless it is forced.` : force ? `${reason ?? ""} Forcing the kill removes the session and leaves the worktree on disk.` : "The session and everything running in it go away. Its worktree stays on disk."; return createPortal(
{ if (e.target === e.currentTarget) onCancel(); }} onKeyDown={(e) => { if (e.key === "Escape") onCancel(); }} >

Kill "{name}"?

{body}

{error &&

{error}

}
, document.body, ); }