From 971f24e017e059b9746450658ebbc1e9b88ed6ad Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Sat, 16 May 2026 06:38:22 +0000 Subject: [PATCH] =?UTF-8?q?feat(web):=20=20assembly=20+=20wir?= =?UTF-8?q?e=20into=20App=20=E2=80=94=20Phase=205=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/App.tsx | 21 +++++------ web/src/monitors/MonitorRail.tsx | 44 ++++++++++++++++++++++ web/tests/component/App.test.tsx | 10 +++++ web/tests/component/MonitorRail.test.tsx | 48 ++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 web/src/monitors/MonitorRail.tsx create mode 100644 web/tests/component/MonitorRail.test.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index 1f949c6..c3142f9 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -10,6 +10,7 @@ import { useSessionList } from '@/state/useSessionList'; import { useApprovalsQueue } from '@/state/useApprovalsQueue'; import { useAgentDefinitions } from '@/state/useAgentDefinitions'; import { useSessionFull } from '@/state/useSessionFull'; +import { MonitorRail } from '@/monitors/MonitorRail'; const UI_VERSION = 'v2.0.0-rc1'; const RUNTIME_VERSION_FALLBACK = 'unknown'; @@ -29,14 +30,6 @@ const paneStyle: CSSProperties = { minHeight: 0, }; -const monitorRailPlaceholder: CSSProperties = { - background: 'var(--bg-page)', - borderLeft: '1px solid var(--hair)', - padding: 16, - fontSize: 11, - color: 'var(--ink-3)', -}; - export function App() { const [activeSid, setActiveSid] = useState(null); @@ -87,9 +80,15 @@ export function App() { onSelect={setActiveSid} /> -
- Ambient monitors (Phase 5) -
+ ; + toolCalls: ToolCall[]; + sessionId: string | null; + onSelectSession: (sid: string) => void; +} + +const wrap: CSSProperties = { + width: 340, + display: 'flex', + flexDirection: 'column', + background: 'var(--bg-page)', + borderLeft: '1px solid var(--hair)', + overflowY: 'auto', + minHeight: 0, +}; + +export function MonitorRail({ + sessions, activeSid, queue, agentsByName, toolCalls, sessionId, onSelectSession, +}: MonitorRailProps) { + return ( + + ); +} diff --git a/web/tests/component/App.test.tsx b/web/tests/component/App.test.tsx index 9c21221..d7ad2a7 100644 --- a/web/tests/component/App.test.tsx +++ b/web/tests/component/App.test.tsx @@ -31,6 +31,16 @@ describe('', () => { status: 200, headers: { 'content-type': 'application/json' }, })); } + if (url.includes('/tools') || url.includes('/lessons')) { + return Promise.resolve(new Response(JSON.stringify([]), { + status: 200, headers: { 'content-type': 'application/json' }, + })); + } + if (url.includes('/health')) { + return Promise.resolve(new Response(JSON.stringify({ status: 'ok' }), { + status: 200, headers: { 'content-type': 'application/json' }, + })); + } return Promise.resolve(new Response('{}', { status: 200 })); }); // @ts-expect-error -- jsdom does not provide EventSource diff --git a/web/tests/component/MonitorRail.test.tsx b/web/tests/component/MonitorRail.test.tsx new file mode 100644 index 0000000..59eca04 --- /dev/null +++ b/web/tests/component/MonitorRail.test.tsx @@ -0,0 +1,48 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { render, screen } from '../_helpers/render'; +import { MonitorRail } from '@/monitors/MonitorRail'; +import type { SessionSummary } from '@/state/useSessionList'; +import type { AgentDefinition, ToolCall } from '@/api/types'; + +const sessions: SessionSummary[] = [ + { id: 'SES-1', status: 'in_progress', label: 'A', created_at: 't0', updated_at: 't1' }, +]; +const queue: SessionSummary[] = []; +const agents: Record = {}; +const tools: ToolCall[] = []; + +describe('', () => { + beforeEach(() => { + global.fetch = vi.fn().mockResolvedValue( + new Response(JSON.stringify([]), { status: 200, headers: { 'content-type': 'application/json' } }), + ); + }); + + it('renders all 6 panel titles', () => { + render( + {}} + />, + ); + expect(screen.getByText(/Selected/)).toBeInTheDocument(); + expect(screen.getByText(/Other Sessions/)).toBeInTheDocument(); + expect(screen.getByText(/Approvals Queue/)).toBeInTheDocument(); + expect(screen.getByText(/Lessons/)).toBeInTheDocument(); + expect(screen.getByText(/Tool Catalog/)).toBeInTheDocument(); + expect(screen.getByText(/System Health/)).toBeInTheDocument(); + }); + + it('renders pinned panels open by default (Selected, Others, Approvals)', () => { + render( + {}} + />, + ); + // Selected pinned with empty body → "Click an agent..." + expect(screen.getByText(/Click an agent, tool, or message/i)).toBeInTheDocument(); + }); +});