Skip to content

chore: refactor TimelineChart for performance#2185

Open
karl-power wants to merge 2 commits intomainfrom
karl/timeline-viewer-perf
Open

chore: refactor TimelineChart for performance#2185
karl-power wants to merge 2 commits intomainfrom
karl/timeline-viewer-perf

Conversation

@karl-power
Copy link
Copy Markdown
Contributor

@karl-power karl-power commented May 4, 2026

Summary

Refactors TimelineChart for performance on traces with thousands of spans. The previous implementation re-rendered the entire chart on every wheel tick because pan/zoom were React state. This branch moves to native horizontal scrolling for pan, an imperative scale ref for zoom, and imperative DOM updates for the X-axis ticks and mouse cursor — so a wheel event no longer triggers a React render of all virtualized rows.

  • Pan is now native horizontal scroll, not drag-to-pan. The previous useDrag handler is gone; users scroll with trackpad/scroll wheel as with any scrollable container. Cmd/Ctrl + scroll still zooms.
  • Single resize handle between label column and events column, instead of one per row.

A Storybook story (TimelineChart.stories.tsx) is added with 1000 synthetic rows for working on this in isolation.

How to test locally or on Vercel

  1. Open a trace with many spans (ideally several hundred). The "Default" Storybook story under Components → TimelineChart also has 1000 synthetic rows for isolated testing.
  2. Scroll vertically — virtualized rows should behave as before; X-axis stays pinned at top, label column stays pinned at left.
  3. Cmd/Ctrl + scroll over the events area to zoom in/out. Confirm:
    • cursor under the mouse stays anchored to the same point in time across the zoom step (no drift)
    • X-axis ticks recompute with the new interval
    • mouse cursor overlay shows the time at the cursor and flips its label to the opposite side past the midpoint
  4. Drag horizontally inside the events area (native scroll bar at bottom, or two-finger swipe). Label column stays in place.
  5. Hover an event bar — Mantine tooltip with the bar's text appears.
  6. On a span with span-events configured, confirm the diamond markers show up inside the bar and have their own tooltip with timestamp + attributes.
  7. On non-Log spans, confirm the duration label (X.YYms) renders beside the bar (right side for early spans, left side for spans past the timeline midpoint).
  8. Drag the resize handle between label column and events column — the label width should resize live across all rows.
  9. Resize the browser window — the mouse-cursor vertical line height should track the new container height (previously stuck at the first-render value).

References

  • Linear Issue: Closes HDX-4145

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 4, 2026

⚠️ No Changeset found

Latest commit: 2dd526c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions Bot added the review/tier-4 Critical — deep review + domain expert sign-off label May 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

🔴 Tier 4 — Critical

Touches auth, data models, config, tasks, OTel pipeline, ClickHouse, or CI/CD.

Why this tier:

  • Large diff: 1272 production lines changed (threshold: 1000)

Review process: Deep review from a domain expert. Synchronous walkthrough may be required.
SLA: Schedule synchronous review within 2 business days.

Stats
  • Production files changed: 11
  • Production lines changed: 1272
  • Branch: karl/timeline-viewer-perf
  • Author: karl-power

To override this classification, remove the review/tier-4 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@vercel
Copy link
Copy Markdown

vercel Bot commented May 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment May 6, 2026 10:09am

Request Review

@karl-power karl-power requested review from a team and elizabetdev May 4, 2026 16:06
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

{"review":"\n## PR Review\n\nReviewed the imperative refactor — math for zoom-anchoring and tick spacing checks out, the wheel handler correctly clamps cursorPx to the events area, and the cursors removal is safe (only DBTraceWaterfallChart passed []).\n\n✅ No critical issues found.\n\nMinor observations (not blockers):\n- ⚠️ TimelineMouseCursor sets style={{ display: 'none' }} on the wrapper as a React inline style, then mutates wrapper.style.display imperatively. Any parent re-render (e.g. mid-drag of the resize handle, since useResizable updates label width state) will re-apply display: 'none' and hide the cursor until the next mousemove/scroll event re-runs recompute(). Consider moving the initial-hidden state to CSS (.mouseCursorWrapper { display: none; }) so React renders don't clobber it — or guard with a ref-tracked visibility flag.\n- ⚠️ TimelineXAxis mutates ticksContainerRef's children imperatively across renders. The SCSS comment warns against adding sibling elements, but the JSX renders <div ref={ticksContainerRef} className={styles.xAxisTicks}></div> — fine today, just fragile if anyone later adds a child node here. Worth a one-line code comment alongside the JSX echoing the SCSS warning.\n- 🧹 DBTraceWaterfallChartContainer still passes an inline onEventClick={(event) => …} arrow on every render, which defeats the memo wrap on TimelineChart. Pre-existing, not introduced here, but the perf-focused refactor is the natural moment to wrap it in useStableCallback/useCallback."}

@karl-power karl-power force-pushed the karl/timeline-viewer-perf branch from c525fbb to 4ffb856 Compare May 4, 2026 16:08
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

E2E Test Results

All tests passed • 158 passed • 3 skipped • 1223s

Status Count
✅ Passed 158
❌ Failed 0
⚠️ Flaky 5
⏭️ Skipped 3

Tests ran across 4 shards in parallel.

View full report →

@karl-power karl-power removed the request for review from a team May 4, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-4 Critical — deep review + domain expert sign-off

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant