dashboard: reverse-virtualize timeline once a run exceeds ~500 events (TanStack Virtual) #973

Closed
opened 2026-05-08 12:17:10 +00:00 by claude-desktop · 1 comment
Collaborator

User story

As an operator viewing a long agent run (200-step refactor, multi-day session), I want the event timeline to stay smooth at 1000+ events with sub-100ms first-paint and stable scroll, without DOM nodes for every event off-screen.

Context

We already use TanStack everywhere; @tanstack/virtual (MIT) is the natural fit. Reverse-virtualize so newest-at-bottom is the natural mode and scrollIntoView for a specific event still works (the scrubber depends on this).

Acceptance criteria

  • Wrap the agent timeline list in useVirtualizer from @tanstack/virtual with reverse-mode enabled.
  • estimateSize per event kind (assistant text ~200 px, tool card collapsed ~64 px, tool card open ~variable — re-measure on toggle).
  • scrollToIndex({align: "center"}) works for scrubber jump.
  • Persist scroll position across drawer reopens (so reopening doesn't snap to bottom unless the user explicitly clicks "scroll to live").
  • Don't pre-virtualize for runs <50 events — measured cost; the virtualizer overhead matters for short runs.

Out of scope

  • Server-side pagination — the runs table caps at 500 events per task today; if/when removed, that's a separate scaling ticket.

Dependencies

  • Depends on the session-scrubber ticket (scrollToIndex integration). Lands together or after.

References

## User story As an operator viewing a long agent run (200-step refactor, multi-day session), I want the event timeline to stay smooth at 1000+ events with sub-100ms first-paint and stable scroll, without DOM nodes for every event off-screen. ## Context We already use TanStack everywhere; `@tanstack/virtual` (MIT) is the natural fit. Reverse-virtualize so newest-at-bottom is the natural mode and `scrollIntoView` for a specific event still works (the scrubber depends on this). ## Acceptance criteria - [ ] Wrap the agent timeline list in `useVirtualizer` from `@tanstack/virtual` with reverse-mode enabled. - [ ] `estimateSize` per event kind (assistant text ~200 px, tool card collapsed ~64 px, tool card open ~variable — re-measure on toggle). - [ ] `scrollToIndex({align: "center"})` works for scrubber jump. - [ ] Persist scroll position across drawer reopens (so reopening doesn't snap to bottom unless the user explicitly clicks "scroll to live"). - [ ] Don't pre-virtualize for runs <50 events — measured cost; the virtualizer overhead matters for short runs. ## Out of scope - Server-side pagination — the runs table caps at 500 events per task today; if/when removed, that's a separate scaling ticket. ## Dependencies - Depends on the session-scrubber ticket (`scrollToIndex` integration). Lands together or after. ## References - TanStack Virtual: https://tanstack.com/virtual/latest
Collaborator

🤖 Auto-assigned to dev (heuristic: area:dashboard + body 1409 bytes (≤ 2 KB) — code role). Reply /unassign to reroute.

🤖 Auto-assigned to **dev** (heuristic: area:dashboard + body 1409 bytes (≤ 2 KB) — code role). Reply `/unassign` to reroute.
Sign in to join this conversation.
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.

Reference
charles/claude-hooks#973
No description provided.