diff --git a/frontend/src/shell/AppShell.tsx b/frontend/src/shell/AppShell.tsx index 4b0b6f47..55071f7b 100644 --- a/frontend/src/shell/AppShell.tsx +++ b/frontend/src/shell/AppShell.tsx @@ -8,6 +8,7 @@ import { SessionMenu } from "./SessionMenu"; import { SessionDocumentsPanel } from "./SessionDocumentsPanel"; import { RenameDialog } from "./RenameDialog"; import { DeleteConfirmDialog } from "./DeleteConfirmDialog"; +import { StopConfirmDialog } from "./StopConfirmDialog"; import { SteerInput, ComposerFooter } from "./SteerInput"; import { WorkflowBar } from "./WorkflowBar"; import { Pencil } from "lucide-react"; @@ -42,6 +43,7 @@ export function AppShell() { const [archiveOpen, setArchiveOpen] = useState(false); const [renameTarget, setRenameTarget] = useState(null); const [deleteTarget, setDeleteTarget] = useState(null); + const [stopConfirm, setStopConfirm] = useState(false); const [collapsedGroups, setCollapsedGroups] = useState>({}); const [renameGroupTarget, setRenameGroupTarget] = useState(null); @@ -68,12 +70,16 @@ export function AppShell() { }); } async function doResume(id: string) { + const s = sessions.find((x) => x.id === id) ?? null; + // Optimistic switch: change to the session view IMMEDIATELY so the click feels + // instant (the resume POST spawns a Pi process and can take seconds). The + // working spinner shows straight away; the backend calls run after. + setPanelSession(null); + resetSession(); + setActiveSessionId(id); try { await resumeSession(id); - setPanelSession(null); - setActiveSessionId(id); - // Optimistic phase paint on resume: colour the re-entry phase immediately, - // before the first gate arrives (mirrors the F1 paint for new questions). + // Optimistic phase paint: colour the re-entry phase before the first gate. // The manifest's `phase` is the 1-based current phase (1..8). try { const m = (await getSession(id)) as { phase?: number }; @@ -84,6 +90,10 @@ export function AppShell() { /* non-fatal: the first gate will set the phase */ } } catch { + // Revert the optimistic switch and restore the panel. + resetSession(); + setActiveSessionId(null); + if (s) setPanelSession(s); toast.error("Failed to resume session."); } } @@ -216,7 +226,7 @@ export function AppShell() { setStopConfirm(true)} inputRef={composerRef} /> @@ -227,7 +237,7 @@ export function AppShell() { {/* Right session rail — symmetric to the portal's left sidebar */} -