feat(ui): monitor task drawer — retire /monitor/tasks + /monitor/task/:id (UI-1) #402

Merged
code-lead merged 2 commits from dev/397 into main 2026-04-26 22:36:41 +00:00
Collaborator

Folds the three-pane task view into a slide-out drawer on /monitor. Stage pills open the drawer in-place via ?detail=taskId; the "Recent tasks" button opens it with the newest task pre-selected. /monitor/tasks and /monitor/task/$taskId redirect to the new URL pattern.

Test plan

  • Click a stage pill in the pipeline list → drawer opens with that task pre-selected
  • Click "Recent tasks" toolbar button → drawer opens with newest task
  • Navigate to /monitor?detail=<taskId> directly → drawer opens + task highlighted
  • Close drawer via ✕ button → ?detail= dropped from URL
  • Navigate to /monitor/tasks → redirects to /monitor?detail=latest + migration toast
  • Navigate to /monitor/task/<id> → redirects to /monitor?detail=<id>
  • Navigate to /monitor/grid → still redirects to /monitor?view=grid
  • bun run qa clean (422 tests pass, biome clean)

Closes #397

Folds the three-pane task view into a slide-out drawer on `/monitor`. Stage pills open the drawer in-place via `?detail=taskId`; the "Recent tasks" button opens it with the newest task pre-selected. `/monitor/tasks` and `/monitor/task/$taskId` redirect to the new URL pattern. ## Test plan - [ ] Click a stage pill in the pipeline list → drawer opens with that task pre-selected - [ ] Click "Recent tasks" toolbar button → drawer opens with newest task - [ ] Navigate to `/monitor?detail=<taskId>` directly → drawer opens + task highlighted - [ ] Close drawer via ✕ button → `?detail=` dropped from URL - [ ] Navigate to `/monitor/tasks` → redirects to `/monitor?detail=latest` + migration toast - [ ] Navigate to `/monitor/task/<id>` → redirects to `/monitor?detail=<id>` - [ ] Navigate to `/monitor/grid` → still redirects to `/monitor?view=grid` - [ ] `bun run qa` clean (422 tests pass, biome clean) Closes #397
feat(ui): add slide-out task drawer to /monitor, retire /monitor/tasks and /monitor/task/:id (UI-1)
All checks were successful
qa / qa (pull_request) Successful in 6m25s
qa / dockerfile (pull_request) Successful in 13s
bf6315da8e
- Add `?detail=taskId` URL param to `/monitor` that opens a two-pane drawer (TaskList + TaskDetail)
- Add `?detail=latest` sentinel for "Recent tasks" toolbar button
- Conditionally render TaskDrawer so SSE subscription is active only while the drawer is open
- Extract `useTaskSSE(queryClient, taskId)` hook shared by the drawer
- Thread `onTaskClick` through StagePill → MiniPipeline → PipelineList/PipelineGrid so
  clicking any stage pill opens the drawer directly without a route navigation
- Replace `monitor.tasks.tsx` with a redirect to `?detail=latest&_moved=tasks`
  (shows a migration toast on arrival)
- Replace `monitor.task.$taskId.tsx` with a redirect to `?detail=$taskId`
- Keep `monitor.grid.tsx` redirect as-is
- Remove "Tasks" nav item from AppShell header
- Update pipeline-list "View tasks instead →" link to `?detail=latest`
- Add optional `selectedId`/`onSelect` overrides to TaskList for drawer-driven selection
- Add redirect tests for the three retired routes
- Document the slide-out drawer pattern in apps/web/CLAUDE.md

Closes #397

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev requested review from reviewer 2026-04-26 20:22:46 +00:00
reviewer requested changes 2026-04-26 20:24:53 +00:00
Dismissed
reviewer left a comment
  • behavior (apps/web/src/routes/monitor.index.tsx, TaskDrawer): fetchHistory() is called with no arguments and TaskDrawer receives no filters prop from MonitorRoute. The AC says the left-pane TaskList must be "scoped to the current pipeline filter (repo/milestone/etc) so operator sees the task subset relevant to what they're viewing." When a user has the pipeline filtered to e.g. ?repo=charles/foo, the drawer still shows all-repo history. Fix: pass filters down to TaskDrawer and either (a) pass repo/milestone to fetchHistory if the API accepts them, or (b) client-side filter the returned list — tasks.filter(t => !filters.repo || t.repo === filters.repo).

  • test-gap (apps/web/src/routes/monitor.index.test.tsx): The AC lists required tests: "drawer opens on ?detail=, closes on X / param drop, list filtering matches pipeline filter, deeplink pasting opens drawer pre-selected." The test file only covers validateSearch (pure function) and the three beforeLoad redirects. No tests exist for the drawer rendering, "latest" sentinel resolution, filter-scoping behaviour, or the migration toast / _moved strip. Add render-level tests (e.g. with @testing-library/react + a mocked fetchHistory) covering at least: drawer mounts when detail is set, unmounts when it's not, and shows the filtered task list.

- **behavior** (`apps/web/src/routes/monitor.index.tsx`, `TaskDrawer`): `fetchHistory()` is called with no arguments and `TaskDrawer` receives no `filters` prop from `MonitorRoute`. The AC says the left-pane TaskList must be "scoped to the **current pipeline filter** (repo/milestone/etc) so operator sees the task subset relevant to what they're viewing." When a user has the pipeline filtered to e.g. `?repo=charles/foo`, the drawer still shows all-repo history. Fix: pass `filters` down to `TaskDrawer` and either (a) pass `repo`/`milestone` to `fetchHistory` if the API accepts them, or (b) client-side filter the returned list — `tasks.filter(t => !filters.repo || t.repo === filters.repo)`. - **test-gap** (`apps/web/src/routes/monitor.index.test.tsx`): The AC lists required tests: "drawer opens on `?detail=`, closes on X / param drop, list filtering matches pipeline filter, deeplink pasting opens drawer pre-selected." The test file only covers `validateSearch` (pure function) and the three `beforeLoad` redirects. No tests exist for the drawer rendering, `"latest"` sentinel resolution, filter-scoping behaviour, or the migration toast / `_moved` strip. Add render-level tests (e.g. with `@testing-library/react` + a mocked `fetchHistory`) covering at least: drawer mounts when `detail` is set, unmounts when it's not, and shows the filtered task list.
fix(ui): scope TaskDrawer task list to pipeline repo filter; add render tests (UI-1)
All checks were successful
qa / qa (pull_request) Successful in 6m27s
qa / dockerfile (pull_request) Successful in 8s
b5bfec5f3e
- Pass `filters` prop to `TaskDrawer`; client-side filter `allTasks` by
  `filters.repo` so the left pane shows only tasks for the active repo.
- Export `TaskDrawer` and add four render-level tests: drawer mounts,
  close button fires `onClose`, conditional mount/unmount, and repo filter
  narrows the visible task list.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Author
Collaborator

Both review points addressed in b5bfec5:

  • behavior: TaskDrawer now accepts a filters prop; client-side filters allTasks by filters.repo (option b — /history has no filter params). MonitorRoute passes its filters memo down.
  • test-gap: Exported TaskDrawer, added four render-level tests: drawer mounts, close button fires onClose, conditional mount/unmount, and repo filter narrows the task list to the matching repo only.
Both review points addressed in b5bfec5: - **behavior**: `TaskDrawer` now accepts a `filters` prop; client-side filters `allTasks` by `filters.repo` (option b — `/history` has no filter params). `MonitorRoute` passes its `filters` memo down. - **test-gap**: Exported `TaskDrawer`, added four render-level tests: drawer mounts, close button fires `onClose`, conditional mount/unmount, and repo filter narrows the task list to the matching repo only.
dev requested review from reviewer 2026-04-26 20:43:24 +00:00
reviewer approved these changes 2026-04-26 22:36:07 +00:00
reviewer left a comment

Both prior findings addressed: filters is now passed through to TaskDrawer with correct client-side repo scoping via useMemo, and the four render-level tests (mount, close callback, conditional rendering, filter scoping) cover the required AC. CI green.

Both prior findings addressed: `filters` is now passed through to `TaskDrawer` with correct client-side `repo` scoping via `useMemo`, and the four render-level tests (mount, close callback, conditional rendering, filter scoping) cover the required AC. CI green.
code-lead deleted branch dev/397 2026-04-26 22:36:44 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!402
No description provided.