PRD: Web UI UX Revamp
Complexity: 7 → HIGH mode
Score breakdown: +3 (10+ files) +2 (new components) +2 (complex state/real-time data)
1. Context
Problem: The Dashboard is overwhelming (too many widgets, duplicate info) and the Scheduling page is hard to understand (5 tabs with unclear purpose distinctions).
Files Analyzed:
web/pages/Dashboard.tsx
web/pages/Scheduling.tsx
web/pages/Logs.tsx
web/components/Sidebar.tsx
web/components/TopBar.tsx
web/App.tsx
web/components/scheduling/ScheduleConfig.tsx
web/components/scheduling/ScheduleTimeline.tsx
web/components/dashboard/AgentStatusBar.tsx
web/store/useStore.ts
web/hooks/useStatusSync.ts
web/components/ui/{Button,Card,Badge,Tabs,Switch}.tsx
Current Behavior (as of 2026-03-21):
- Dashboard: 4 stat cards + AgentStatusBar (compact 6-agent grid) + next automation teaser + GitHub Board widget — already cleaned up
- Scheduling: 5-tab layout (Overview, Schedules, Crontab, Parallelism, individual job tabs) — still complex and hard to navigate
- Sidebar: section labels (Overview / Work / Automation / Config) — already grouped
- TopBar: Bell icon with red dot but no implementation behind it; no Settings icon — mostly clean
- Shared state:
useStatusSync in App.tsx writes to Zustand store; all pages read from store — already unified
- Logs: reads
status from store, independent log polling — correct
2. Completed Phases
✅ Phase 0: Shared status state
useStatusSync hook exists at web/hooks/useStatusSync.ts
status: IStatusSnapshot | null in web/store/useStore.ts
useStatusSync() called in App.tsx — single SSE subscription app-wide
- Dashboard and Logs both read from store
✅ Phase 1: Dashboard Cleanup
- 4 stat cards: Board Ready, In Progress, Open PRs, Automation Status
AgentStatusBar (web/components/dashboard/AgentStatusBar.tsx) — 6-agent compact grid
- "System Status" card removed
- "Scheduling summary" card removed
- "Next automation" teaser line added
✅ Phase 3: Sidebar Navigation Grouping
- Section labels: OVERVIEW / WORK / AUTOMATION / CONFIG
- Labels hidden when collapsed, visible when expanded
- "Scheduling" nav item present under AUTOMATION
✅ Phase 4: TopBar Cleanup
- Settings icon already removed from TopBar
- Bell icon present (no Settings duplication)
3. Remaining Work
Phase 2 (Incomplete): Flatten Scheduling Page
Status: ScheduleConfig component extracted ✅ — but Scheduling.tsx still uses 5 tabs ❌
Problem: Scheduling has tabs: Overview, Schedules, Crontab, Parallelism, plus per-job sub-tabs. "Overview" and "Schedules" are still confusing. "Crontab" and "Parallelism" are obscure labels for advanced config that buries the primary use case (seeing what runs when).
Files (max 4):
web/pages/Scheduling.tsx — replace Tabs with flat scrollable sections
Implementation:
Delete the <Tabs> component and activeTab state. New flat page structure:
Section A: Global Controls
[Automation: Active/Paused] [Schedule bundle name] [Pause/Resume button]
Section B: Agent Schedule Cards
6 cards (2-col grid): icon + name + Switch toggle + "every 3h" desc + next run countdown + start delay badge
Section C: Configure Schedules ← was hidden in "Schedules" tab
<ScheduleConfig /> with template picker / custom cron inputs
[Save & Install] button
Section D: Cron Entries ← was "Crontab" tab
Installed crontab entries table (collapsible, default collapsed)
Enable/disable/remove per entry
Section E: Parallelism & Queue ← was "Parallelism" tab
Queue mode (Auto/Manual), global max concurrency, provider buckets
(collapsible, default collapsed)
Tests Required:
| Test File |
Test Name |
Assertion |
web/src/__tests__/Scheduling.test.tsx |
renders all 6 agent cards without tabs |
6 agent name elements, no Tabs component |
web/src/__tests__/Scheduling.test.tsx |
ScheduleConfig section visible without clicking tabs |
Schedule config rendered directly |
web/src/__tests__/Scheduling.test.tsx |
crontab section collapsed by default |
Crontab entries not visible initially |
web/src/__tests__/Scheduling.test.tsx |
expanding crontab section shows entries |
Entries visible after expand click |
User Verification:
- Action: Open
/scheduling
- Expected: No tabs. Scroll down past agents → see "Configure Schedules" inline. Crontab and Parallelism are collapsed advanced sections at the bottom. No redirect to Settings needed.
Checkpoint: Run prd-work-reviewer after this phase.
Phase 5: Command Palette (Cmd+K)
Why: Power users trigger agents, navigate pages, and manage schedules frequently. Every action currently requires 2–4 clicks through the UI. A command palette eliminates navigation overhead and makes the tool feel fast.
Files (max 5):
web/components/CommandPalette.tsx — new component
web/hooks/useCommandPalette.ts — keyboard shortcut registration + open/close state
web/App.tsx — render <CommandPalette /> at root + useCommandPalette()
web/store/useStore.ts — add commandPaletteOpen: boolean + setCommandPaletteOpen
Component design:
┌─────────────────────────────────────────────────┐
│ 🔍 Search commands or navigate... │
├─────────────────────────────────────────────────┤
│ ── NAVIGATE ── │
│ → Dashboard ⌘1 │
│ → Logs ⌘2 │
│ → Board ⌘3 │
│ → Scheduling ⌘4 │
│ → Settings ⌘, │
├─────────────────────────────────────────────────┤
│ ── AGENTS ── │
│ ▶ Run Executor [only if idle] │
│ ■ Stop Executor [only if running] │
│ ▶ Run Reviewer │
│ ▶ Run QA │
│ ▶ Run Auditor │
│ ▶ Run Planner │
├─────────────────────────────────────────────────┤
│ ── SCHEDULING ── │
│ ⏸ Pause Automation [only if active] │
│ ▶ Resume Automation [only if paused] │
└─────────────────────────────────────────────────┘
Implementation:
Tests Required:
| Test File |
Test Name |
Assertion |
web/src/__tests__/CommandPalette.test.tsx |
opens on Cmd+K |
Palette visible after keydown event |
web/src/__tests__/CommandPalette.test.tsx |
closes on Escape |
Palette hidden after Escape |
web/src/__tests__/CommandPalette.test.tsx |
filters commands by search term |
Only matching commands shown |
web/src/__tests__/CommandPalette.test.tsx |
navigates to page on Enter |
navigate called with correct path |
web/src/__tests__/CommandPalette.test.tsx |
shows Run agent only when idle |
Run command absent when process running |
User Verification:
- Action: Press
Cmd+K on any page
- Expected: Palette opens. Type "exec" → "Run Executor" appears. Press Enter → executor triggered. Press Escape → closes.
Checkpoint: Run prd-work-reviewer after this phase.
Phase 6: Notification / Activity Center
Why: The TopBar Bell icon has a red dot but no implementation. Users have no way to see what happened recently (which PRDs ran, which failed, when schedules last fired) without digging through Logs. An activity feed surfaces this at a glance.
Files (max 5):
web/components/ActivityCenter.tsx — slide-out panel
web/hooks/useActivityFeed.ts — assembles activity events from status + logs API
web/components/TopBar.tsx — wire Bell button to open panel
web/store/useStore.ts — add activityCenterOpen: boolean + setActivityCenterOpen
Activity event types (derive from existing data, no new API needed):
type IActivityEvent =
| { type: 'agent_completed'; agent: string; duration: string; prd?: string; ts: Date }
| { type: 'agent_failed'; agent: string; error: string; ts: Date }
| { type: 'schedule_fired'; agent: string; ts: Date }
| { type: 'automation_paused' | 'automation_resumed'; ts: Date }
| { type: 'pr_opened'; number: number; title: string; ts: Date }
Panel design (slide-out from right, 360px wide):
┌─ Activity ─────────────────── [×] ─┐
│ Today │
│ ● Executor completed PRD-42 2m ago│
│ ● PR #18 opened 5m ago │
│ ● Reviewer completed 12m ago │
│ ─ Yesterday ─ │
│ ● Automation paused 3h ago │
│ ● QA failed: exit code 1 5h ago │
└────────────────────────────────────┘
Implementation:
Tests Required:
| Test File |
Test Name |
Assertion |
web/src/__tests__/ActivityCenter.test.tsx |
slides in when open |
Panel has translate-x-0 class |
web/src/__tests__/ActivityCenter.test.tsx |
shows completed event when process transitions running→idle |
Completed event rendered |
web/src/__tests__/ActivityCenter.test.tsx |
bell dot hidden when panel open |
Red dot not visible with panel open |
User Verification:
- Action: Click the Bell icon
- Expected: Right panel slides in showing recent agent completions and PR events. Bell dot disappears after opening.
Checkpoint: Run prd-work-reviewer after this phase.
Phase 7: Log Page UX — Filter Bar + Agent Tabs
Why: Logs page currently shows a raw log dump with no way to filter by agent. When multiple agents run, logs interleave and become hard to read. Users must manually scan for the agent they care about.
Files (max 4):
web/pages/Logs.tsx — add filter bar + per-agent view
web/components/logs/LogFilterBar.tsx — new component
Implementation:
Result layout:
[All] [Executor ●] [Reviewer] [QA] [Auditor] [Planner] [Analytics]
🔍 Search logs... [Errors only ○]
─────────────────────────────────────────────────────────
2026-03-21 14:32:01 [executor] Starting PRD execution...
2026-03-21 14:32:05 [executor] Reading board...
Tests Required:
| Test File |
Test Name |
Assertion |
web/src/__tests__/LogFilterBar.test.tsx |
renders all 6 agent pills plus All |
7 pills visible |
web/src/__tests__/LogFilterBar.test.tsx |
shows running dot on active agent pill |
Pulse element present for running agent |
web/src/__tests__/Logs.test.tsx |
filters log lines by selected agent |
Only executor lines shown when executor pill active |
web/src/__tests__/Logs.test.tsx |
filters by search term |
Only matching lines shown |
web/src/__tests__/Logs.test.tsx |
errors only toggle filters non-error lines |
Only error lines shown |
User Verification:
- Action: Open
/logs, click "Executor" pill
- Expected: Only lines prefixed with
[executor] shown. Other agents' lines hidden. Running agent has a pulsing dot on its pill.
Checkpoint: Run prd-work-reviewer after this phase.
4. Integration Points
Entry points: existing routes (/, /scheduling, /logs, sidebar, TopBar bell)
No new routes needed
No new API surface needed (all data derived from existing status + logs APIs)
User-facing: YES — all changes are visual
5. Verification Strategy
Each phase: yarn verify + phase-specific tests + prd-work-reviewer checkpoint.
cd /home/joao/projects/night-watch-cli
yarn verify
yarn workspace night-watch-web test --run
6. Acceptance Criteria
Original phases (all complete)
Remaining
PRD: Web UI UX Revamp
Complexity: 7 → HIGH mode
Score breakdown: +3 (10+ files) +2 (new components) +2 (complex state/real-time data)
1. Context
Problem: The Dashboard is overwhelming (too many widgets, duplicate info) and the Scheduling page is hard to understand (5 tabs with unclear purpose distinctions).
Files Analyzed:
web/pages/Dashboard.tsxweb/pages/Scheduling.tsxweb/pages/Logs.tsxweb/components/Sidebar.tsxweb/components/TopBar.tsxweb/App.tsxweb/components/scheduling/ScheduleConfig.tsxweb/components/scheduling/ScheduleTimeline.tsxweb/components/dashboard/AgentStatusBar.tsxweb/store/useStore.tsweb/hooks/useStatusSync.tsweb/components/ui/{Button,Card,Badge,Tabs,Switch}.tsxCurrent Behavior (as of 2026-03-21):
useStatusSyncinApp.tsxwrites to Zustand store; all pages read from store — already unifiedstatusfrom store, independent log polling — correct2. Completed Phases
✅ Phase 0: Shared status state
useStatusSynchook exists atweb/hooks/useStatusSync.tsstatus: IStatusSnapshot | nullinweb/store/useStore.tsuseStatusSync()called inApp.tsx— single SSE subscription app-wide✅ Phase 1: Dashboard Cleanup
AgentStatusBar(web/components/dashboard/AgentStatusBar.tsx) — 6-agent compact grid✅ Phase 3: Sidebar Navigation Grouping
✅ Phase 4: TopBar Cleanup
3. Remaining Work
Phase 2 (Incomplete): Flatten Scheduling Page
Status:
ScheduleConfigcomponent extracted ✅ — butScheduling.tsxstill uses 5 tabs ❌Problem: Scheduling has tabs: Overview, Schedules, Crontab, Parallelism, plus per-job sub-tabs. "Overview" and "Schedules" are still confusing. "Crontab" and "Parallelism" are obscure labels for advanced config that buries the primary use case (seeing what runs when).
Files (max 4):
web/pages/Scheduling.tsx— replace Tabs with flat scrollable sectionsImplementation:
Delete the
<Tabs>component andactiveTabstate. New flat page structure:activeTabstate and<Tabs>import<ScheduleConfig />)<details>or state toggle)navigate('/settings?tab=schedules...')redirect withscrollIntoViewto Section C anchorexpandedCrontab+expandedParallelismlocal state (defaultfalse) for collapsible sectionsScheduleTimelinemoves into Section B as a visual beneath the agent cardsTests Required:
web/src/__tests__/Scheduling.test.tsxrenders all 6 agent cards without tabsweb/src/__tests__/Scheduling.test.tsxScheduleConfig section visible without clicking tabsweb/src/__tests__/Scheduling.test.tsxcrontab section collapsed by defaultweb/src/__tests__/Scheduling.test.tsxexpanding crontab section shows entriesUser Verification:
/schedulingCheckpoint: Run
prd-work-reviewerafter this phase.Phase 5: Command Palette (Cmd+K)
Why: Power users trigger agents, navigate pages, and manage schedules frequently. Every action currently requires 2–4 clicks through the UI. A command palette eliminates navigation overhead and makes the tool feel fast.
Files (max 5):
web/components/CommandPalette.tsx— new componentweb/hooks/useCommandPalette.ts— keyboard shortcut registration + open/close stateweb/App.tsx— render<CommandPalette />at root +useCommandPalette()web/store/useStore.ts— addcommandPaletteOpen: boolean+setCommandPaletteOpenComponent design:
Implementation:
useCommandPalette.ts: registerskeydownlistener forCmd+K/Ctrl+K; writescommandPaletteOpento storeCommandPalette.tsx: modal overlay (semi-transparent backdrop), search input, grouped command list↑/↓to move,Enterto execute,Escto closeuseNavigate), trigger agent (callstriggerJobAPI), toggle automationuseStore(s => s.status)— only show "Run X" if X is idleApp.tsx: add<CommandPalette />after routes, calluseCommandPalette()useStore.ts: addcommandPaletteOpen+setCommandPaletteOpento storeTests Required:
web/src/__tests__/CommandPalette.test.tsxopens on Cmd+Kweb/src/__tests__/CommandPalette.test.tsxcloses on Escapeweb/src/__tests__/CommandPalette.test.tsxfilters commands by search termweb/src/__tests__/CommandPalette.test.tsxnavigates to page on Enterweb/src/__tests__/CommandPalette.test.tsxshows Run agent only when idleUser Verification:
Cmd+Kon any pageCheckpoint: Run
prd-work-reviewerafter this phase.Phase 6: Notification / Activity Center
Why: The TopBar Bell icon has a red dot but no implementation. Users have no way to see what happened recently (which PRDs ran, which failed, when schedules last fired) without digging through Logs. An activity feed surfaces this at a glance.
Files (max 5):
web/components/ActivityCenter.tsx— slide-out panelweb/hooks/useActivityFeed.ts— assembles activity events from status + logs APIweb/components/TopBar.tsx— wire Bell button to open panelweb/store/useStore.ts— addactivityCenterOpen: boolean+setActivityCenterOpenActivity event types (derive from existing data, no new API needed):
Panel design (slide-out from right, 360px wide):
Implementation:
useStore.ts: addactivityCenterOpen+setActivityCenterOpenuseActivityFeed.ts: buildsIActivityEvent[]by watchingstatuschanges in store (compare previous vs next — if a process transitions running→idle, it "completed") + fetching recent log entries on mountActivityCenter.tsx: fixed right-side panel,translate-x-fullwhen closed,translate-x-0when open; grouped by day; each event is an icon + description + relative timeTopBar.tsx: Bell button callssetActivityCenterOpen(true); red dot shows only whenactivityEvents.length > 0and panel is closed (i.e., unread events)Tests Required:
web/src/__tests__/ActivityCenter.test.tsxslides in when openweb/src/__tests__/ActivityCenter.test.tsxshows completed event when process transitions running→idleweb/src/__tests__/ActivityCenter.test.tsxbell dot hidden when panel openUser Verification:
Checkpoint: Run
prd-work-reviewerafter this phase.Phase 7: Log Page UX — Filter Bar + Agent Tabs
Why: Logs page currently shows a raw log dump with no way to filter by agent. When multiple agents run, logs interleave and become hard to read. Users must manually scan for the agent they care about.
Files (max 4):
web/pages/Logs.tsx— add filter bar + per-agent viewweb/components/logs/LogFilterBar.tsx— new componentImplementation:
LogFilterBar.tsx: horizontal pill bar showing all 6 agents + "All" optionLogs.tsxchanges:selectedAgent: string | nullstate (null = "All")searchTerm: stringstateerrorsOnly: booleanstatelogLinesbefore render: by agent prefix (log lines are prefixed with[executor],[reviewer]etc.), bysearchTerm, by error keywords iferrorsOnly<LogFilterBar>above the log outputLog line parsing: each line starts with
[agent-name]prefix — extract agent name from this prefix to drive per-agent filtering (no API change needed)Result layout:
Tests Required:
web/src/__tests__/LogFilterBar.test.tsxrenders all 6 agent pills plus Allweb/src/__tests__/LogFilterBar.test.tsxshows running dot on active agent pillweb/src/__tests__/Logs.test.tsxfilters log lines by selected agentweb/src/__tests__/Logs.test.tsxfilters by search termweb/src/__tests__/Logs.test.tsxerrors only toggle filters non-error linesUser Verification:
/logs, click "Executor" pill[executor]shown. Other agents' lines hidden. Running agent has a pulsing dot on its pill.Checkpoint: Run
prd-work-reviewerafter this phase.4. Integration Points
5. Verification Strategy
Each phase:
yarn verify+ phase-specific tests +prd-work-reviewercheckpoint.6. Acceptance Criteria
Original phases (all complete)
statusin Zustand; Dashboard + Logs read from storeRemaining
Cmd+Kopens command palette; can trigger agents + navigate without mouseyarn verifypasses after each phase