feat(web): Gantt timeline view for per-issue pipeline (M19-5) #204
No reviewers
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/claude-hooks!204
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "dev/178"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
/app/monitor/issue/<owner>/<repo>/<n>/gantt— horizontal Gantt chart showing when each pipeline stage ran, queue wait gaps, and a live-growing bar for the running stagePipelineGanttcomponent +buildGanttData()projection; bars coloured by the sharedstage-*palette; gray gap connectors; force-merge ★ and review-loop ↺N annotations; X-axis tick labelspipeline-gantt.test.tsxcovering data projection (width proportionality, gap detection, running flag) and DOM rendering (pulse class, annotations, gap connectors)pipeline-list.tsx(testidpipeline-row-timeline-<repo>-<n>)routeTree.gen.tsupdated with the new route registrationTest plan
bun run test src/components/pipeline-gantt.test.tsx— 28/28 passpipeline-list.test.tsx— 26/26 pass (no regression)/app/monitor→ verify "Timeline →" link appears on each issue row/app/monitor/issue/<owner>/<repo>/<n>/ganttloadsCloses #178
🤖 Generated with Claude Code
57d2e02f13a78610d299179c935905bc0da557c2Review — M19-5 Gantt timeline view
CI: ✅ green (run #390,
f6a676e)Acceptance criteria: all six ACs from issue #178 are met.
Test coverage: 28 new tests, fixture well-designed, no regressions in
pipeline-list.test.tsx.Two issues to fix before merging.
Bug —
GanttBarRowbypasses the injectednowfor the running-bar duration labelFile:
apps/web/src/components/pipeline-gantt.tsxThe
PipelineGanttPropsdoc-comment explicitly states thatnowexists so callers can inject a frozen timestamp for deterministic rendering.buildGanttDataand bar-width calculations correctly use the injected value. However, the duration label for a running stage inGanttBarRowhard-callsDate.now():Effect:
now(deterministic).Date.now()(non-deterministic).On a 1-second tick the drift is minor for end-users, but it makes the label untestable with a frozen
now— the injected pattern exists precisely to avoid this. If a future test asserts the duration label for a running stage it will flake.Fix: pass
nowdown toGanttBarRowand use it in the label:In
PipelineGantt:Dead prop —
totalMsis destructured but never used insideGanttBarRowFile:
apps/web/src/components/pipeline-gantt.tsxGanttBarRowPropsdeclarestotalMs: numberand the function destructures it, but neither the gap connector nor the stage bar inside the component use it — all positions are already expressed asleftPct/widthPctpercentages computed inbuildGanttData. The prop should be removed (and its callsite inPipelineGanttcleaned up accordingly).Everything else looks solid: SSE patch logic, gap-threshold filter,
MIN_BAR_PCTfloor,originMsderivation, tick cleanup on unmount, query-cache sharing with the graph route, empty/loading/not-found states, and the biome override scoped to test files only.@ -0,0 +190,4 @@}return { bars, gaps, totalMs, originMs };}Dead prop:
totalMsis declared inGanttBarRowProps, destructured, and passed at the call-site (<GanttBarRow … totalMs={totalMs} />), but it is never referenced inside the component body. All positions are alreadyleftPct/widthPctpercentages frombuildGanttData. Remove it from the interface, the destructure, and the call-site.Review — Round 2 (delta only)
CI: ✅ green (run #391,
91136a1)Both issues from round 1 are fixed:
GanttBarRownow prop —GanttBarRowPropsnow declaresnow: numberwith a doc-comment explaining its purpose, the duration label usesnowinstead ofDate.now(), and the callsite passesnow={now}. ✅Dead
totalMsprop removed —GanttBarRowPropsno longer declarestotalMs, the function no longer destructures it, and the callsite is clean. ✅No regressions introduced by the fix. LGTM.