feat(dashboard): reverse-virtualize event timeline with TanStack Virtual #1005

Merged
reviewer merged 1 commit from dev/973 into main 2026-05-08 22:12:13 +00:00
Collaborator

Wraps the agent event timeline in useVirtualizer (TanStack Virtual v3) for runs with ≥ 50 events; falls back to plain DOM rendering below that threshold.

Test plan

  • Open a task with < 50 events — plain DOM path, behaviour unchanged, existing tests pass
  • Open a task with ≥ 50 events — virtual path active; scroll is smooth, only visible rows are in the DOM
  • Drag the session scrubber — scrollToIndex({align:"center"}) centres the target group in the viewport; collapsed tool-call groups auto-expand when the target lands inside one
  • Close and reopen the task drawer — scroll position restores to the saved offset rather than snapping to the bottom
  • just qa clean

Closes #973

Wraps the agent event timeline in `useVirtualizer` (TanStack Virtual v3) for runs with ≥ 50 events; falls back to plain DOM rendering below that threshold. ## Test plan - Open a task with < 50 events — plain DOM path, behaviour unchanged, existing tests pass - Open a task with ≥ 50 events — virtual path active; scroll is smooth, only visible rows are in the DOM - Drag the session scrubber — `scrollToIndex({align:"center"})` centres the target group in the viewport; collapsed tool-call groups auto-expand when the target lands inside one - Close and reopen the task drawer — scroll position restores to the saved offset rather than snapping to the bottom - `just qa` clean Closes #973
dev self-assigned this 2026-05-08 22:04:34 +00:00
feat(dashboard): reverse-virtualize timeline with TanStack Virtual (#973)
All checks were successful
qa / sql-layer-check (pull_request) Successful in 7s
qa / dockerfile (pull_request) Successful in 8s
qa / i18n-string-check (pull_request) Successful in 10s
qa / db-schema (pull_request) Successful in 16s
qa / qa-1 (pull_request) Successful in 3m39s
qa / qa (pull_request) Successful in 0s
f503cd3b67
Wrap the agent event timeline in `useVirtualizer` (TanStack Virtual v3)
for runs with ≥ 50 events; fall back to plain DOM rendering below that
threshold to avoid virtualizer overhead on short runs.

- `estimateSize` by event kind: assistant/approval_pending ~200 px,
  collapsed tool_call group ~40 px, others ~64 px; `measureElement`
  re-measures actual heights so expanded groups stay correct.
- Scrubber `scrollToIndex({align:"center"})` wired through for the
  virtual path; DOM-query scroll-into-view kept for the plain path.
- Scroll position persisted in a module-level cache keyed by `persistKey`
  (task ID); restored via `useLayoutEffect` on drawer reopen so the
  viewport doesn't snap to the bottom.
- `task-detail.tsx`: passes `persistKey={task.id}` to `<EventLog>`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev force-pushed dev/973 from f503cd3b67
All checks were successful
qa / sql-layer-check (pull_request) Successful in 7s
qa / dockerfile (pull_request) Successful in 8s
qa / i18n-string-check (pull_request) Successful in 10s
qa / db-schema (pull_request) Successful in 16s
qa / qa-1 (pull_request) Successful in 3m39s
qa / qa (pull_request) Successful in 0s
to 904623445c
All checks were successful
qa / sql-layer-check (pull_request) Successful in 14s
qa / dockerfile (pull_request) Successful in 14s
qa / i18n-string-check (pull_request) Successful in 14s
qa / db-schema (pull_request) Successful in 18s
qa / qa-1 (pull_request) Successful in 2m2s
qa / qa (pull_request) Successful in 0s
2026-05-08 22:09:30 +00:00
Compare
dev requested review from reviewer 2026-05-08 22:10:36 +00:00
reviewer approved these changes 2026-05-08 22:12:04 +00:00
reviewer left a comment

Correct virtualizer integration — hook always called (rules compliance), count=0 no-op on plain path, scrubber→group mapping, scroll persistence all implemented properly. CI green.

Nits (not blocking): scrollPositionCache is unbounded — consider capping at ~100 entries; baseIdx inner loop is O(N) but only over visible items so impact is negligible.

Correct virtualizer integration — hook always called (rules compliance), count=0 no-op on plain path, scrubber→group mapping, scroll persistence all implemented properly. CI green. Nits (not blocking): `scrollPositionCache` is unbounded — consider capping at ~100 entries; `baseIdx` inner loop is O(N) but only over visible items so impact is negligible.
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!1005
No description provided.