- NavSessions: left nav listing sessions via listSessions (TanStack Query), clicking resumes via resumeSession and sets active; active item highlighted - NewSessionDialog: ShadCn dialog with question textarea, workspace native select (from listWorkspaces), graceful model field (dropdown when models list is non-empty, free-text input when empty per §9 degradation), optional thinking/provider fields; try/catch surfaces errors inline - SteerInput: text input + button POSTs to postSteer, clears on send, supports Enter key; only shown when a session is active - WorkflowBar: renders 8 phases (F1..F8) with data-active highlighting driven by useSessionStore.currentPhase (new store field + setPhase action) - AppShell: wires all four components; right artifact sidebar now collapsible via a toggle button (useState sidebarOpen); replaces old "Nuova domanda" button with NewSessionDialog trigger - f1-loop.test: updated to drive through the new dialog flow (open → fill question → submit → wait for SSE → respond) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
import { useState } from "react";
|
|
import { useSessionStream } from "../stream/useSessionStream";
|
|
import { WidgetHost } from "./WidgetHost";
|
|
import { NavSessions } from "./NavSessions";
|
|
import { NewSessionDialog } from "./NewSessionDialog";
|
|
import { SteerInput } from "./SteerInput";
|
|
import { WorkflowBar } from "./WorkflowBar";
|
|
|
|
export function AppShell() {
|
|
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
|
|
const [sidebarOpen, setSidebarOpen] = useState(true);
|
|
|
|
useSessionStream(activeSessionId);
|
|
|
|
function handleSessionSelect(id: string) {
|
|
setActiveSessionId(id);
|
|
}
|
|
|
|
function handleCreated(id: string) {
|
|
setActiveSessionId(id);
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-screen">
|
|
{/* Left nav: new session button + sessions list */}
|
|
<aside className="w-48 border-r p-2 flex flex-col gap-2">
|
|
<NewSessionDialog onCreated={handleCreated} />
|
|
<NavSessions
|
|
activeSessionId={activeSessionId}
|
|
onSessionSelect={handleSessionSelect}
|
|
/>
|
|
</aside>
|
|
|
|
<div className="flex flex-col flex-1 min-w-0">
|
|
{/* Top workflow bar */}
|
|
<header className="border-b px-4 py-2 flex items-center gap-4">
|
|
<WorkflowBar />
|
|
<button
|
|
className="ml-auto text-xs text-muted-foreground hover:text-foreground border rounded px-2 py-0.5"
|
|
onClick={() => setSidebarOpen((v) => !v)}
|
|
aria-label={sidebarOpen ? "Chiudi sidebar" : "Apri sidebar"}
|
|
>
|
|
{sidebarOpen ? "←" : "→"}
|
|
</button>
|
|
</header>
|
|
|
|
{/* Center: chat + steer input */}
|
|
<main className="flex-1 overflow-auto p-4 flex flex-col gap-2">
|
|
<WidgetHost sessionId={activeSessionId} />
|
|
{activeSessionId && <SteerInput sessionId={activeSessionId} />}
|
|
</main>
|
|
</div>
|
|
|
|
{/* Right artifact sidebar — collapsible */}
|
|
{sidebarOpen && (
|
|
<aside className="w-64 border-l p-2 flex flex-col">
|
|
<p className="text-xs text-muted-foreground">Artefatti</p>
|
|
</aside>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|