Skip to content

feat: add trace timeline minimap#2552

Merged
kodiakhq[bot] merged 3 commits into
mainfrom
HDX-3951-add-trace-minimap
Jul 1, 2026
Merged

feat: add trace timeline minimap#2552
kodiakhq[bot] merged 3 commits into
mainfrom
HDX-3951-add-trace-minimap

Conversation

@karl-power

@karl-power karl-power commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • New TimelineMinimap: time axis + one bar per span over the full trace range. Brush to zoom, drag the viewport rect to pan, drag its edges to resize, double-click or reset button to zoom out. Dimmed overlay + framed rect show the current viewport.
  • New TimelineViewportController in TimelineChart — imperative bridge (getState, rAF-throttled subscribe, zoomToRange, panToOffset, reset) exposed via onReady, so the minimap reads/drives the chart's scroll-based zoom/pan without re-rendering virtualized rows. Wheel-zoom refactored through a shared commitViewport so wheel, native scroll, and minimap stay in sync.
  • Extracted getMaxEventValue so chart and minimap derive an identical range.
  • Wired into DBTraceWaterfallChart (shown once rows load with visible spans).

Screenshots or video

Screen.Recording.2026-06-30.at.16.20.44.mov

How to test on Vercel preview

Preview routes: /search

Steps:

  1. Open the trace viewer and explore a timeline with the minimap.

References

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Jul 1, 2026 7:00am
hyperdx-storybook Ready Ready Preview, Comment Jul 1, 2026 7:00am

Request Review

@github-actions github-actions Bot added the review/tier-3 Standard — full human review required label Jun 30, 2026
@changeset-bot

changeset-bot Bot commented Jun 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d18f5a1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

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

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

🟡 Tier 3 — Standard

Introduces new logic, modifies core functionality, or touches areas with non-trivial risk.

Why this tier:

  • Diff size: 677 production lines changed (Tier 2 max: < 250)

Review process: Full human review — logic, architecture, edge cases.
SLA: First-pass feedback within 1 business day.

Stats
  • Production files changed: 6
  • Production lines changed: 677 (+ 244 in test files, excluded from tier calculation)
  • Branch: HDX-3951-add-trace-minimap
  • Author: karl-power

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

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 223 passed • 3 skipped • 1489s

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

Tests ran across 4 shards in parallel.

View full report →

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a TimelineMinimap component above the waterfall chart — a compact time-axis bar chart with brush-to-zoom, drag-to-pan, and resize-handle interactions — wired to the existing TimelineChart through a new imperative TimelineViewportController bridge that avoids re-rendering virtualised rows.

  • TimelineViewportController exposes getState, subscribe (rAF-throttled), zoomToRange, panToOffset, and reset; the stable controller is constructed once per mount and handed to the parent via an onReady prop.
  • TimelineMinimap mirrors the chart viewport through a subscription and drives zoom/pan commands back, with pointer-capture drag handling for pan, left/right resize, and brush modes; getMaxEventValue is extracted so both components derive an identical timeline range.
  • DBTraceWaterfallChartContainer stores the controller in state and conditionally renders the minimap once rows with visible spans are loaded.

Confidence Score: 5/5

Safe to merge — the minimap is entirely additive and isolated behind a showMinimap guard; the imperative controller bridge does not alter existing chart rendering or data paths.

Changes are additive: a new component, a new utility function, and an optional onReady prop. The two previously flagged issues (stale labelWidth notification and missing maxVal > 0 guard on bars) are both addressed in this version. Remaining findings are a cosmetic cursor UX nit and a minor redundant layout query.

TimelineMinimap.tsx — pointer-capture cursor reset on drag end and the double getBoundingClientRect call per pointer-move are the only loose ends.

Important Files Changed

Filename Overview
packages/app/src/components/TimelineChart/TimelineMinimap.tsx New minimap component with pointer-capture drag for pan/resize/brush modes; previous reviewer concerns (maxVal guard) are resolved. Minor: cursor not reset on pointer-up.
packages/app/src/components/TimelineChart/TimelineChart.tsx Adds TimelineViewportController bridge, commitViewport refactor, and labelWidth/scroll notification effects; logic is sound and previously flagged stale-notify bug is fixed.
packages/app/src/components/DBTraceWaterfallChart.tsx Wires minimap into the waterfall container; showMinimap condition and onReady wiring are correct.
packages/app/src/components/TimelineChart/utils.ts Extracts getMaxEventValue as a pure utility so both TimelineChart and TimelineMinimap derive the same range; well-tested.
packages/app/src/components/TimelineChart/tests/TimelineMinimap.test.tsx Covers brush-zoom, pan, resize, double-click reset, and reset-button visibility with a clean PointerEvent polyfill and deterministic getBoundingClientRect mock.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant DBC as DBTraceWaterfallChartContainer
    participant TC as TimelineChart
    participant TM as TimelineMinimap

    DBC->>TC: "render (onReady=setViewportController)"
    TC->>TC: create controllerRef on mount
    TC-->>DBC: onReady(controller) [useEffect]
    DBC->>DBC: setViewportController(controller)
    DBC->>TM: "render (controller=controller)"
    TM->>TC: controller.subscribe(update)

    Note over TC,TM: User scrolls / wheel-zooms
    TC->>TC: commitViewport(scale, scrollLeft)
    TC->>TC: notifyViewport() [rAF-throttled]
    TC-->>TM: subscriber callback fires
    TM->>TC: controller.getState()
    TC-->>TM: "{scale, offsetFrac, viewportWidthFrac}"
    TM->>TM: setViewport(state) → re-render rect

    Note over TC,TM: User brushes minimap
    TM->>TM: "handlePointerDown → dragMode=brush"
    TM->>TM: handlePointerMove → setBrushRange (visual only)
    TM->>TC: controller.zoomToRange(start, end) [on pointerUp]
    TC->>TC: commitViewport(newScale, newScrollLeft)
    TC-->>TM: subscriber notified → rect updates
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant DBC as DBTraceWaterfallChartContainer
    participant TC as TimelineChart
    participant TM as TimelineMinimap

    DBC->>TC: "render (onReady=setViewportController)"
    TC->>TC: create controllerRef on mount
    TC-->>DBC: onReady(controller) [useEffect]
    DBC->>DBC: setViewportController(controller)
    DBC->>TM: "render (controller=controller)"
    TM->>TC: controller.subscribe(update)

    Note over TC,TM: User scrolls / wheel-zooms
    TC->>TC: commitViewport(scale, scrollLeft)
    TC->>TC: notifyViewport() [rAF-throttled]
    TC-->>TM: subscriber callback fires
    TM->>TC: controller.getState()
    TC-->>TM: "{scale, offsetFrac, viewportWidthFrac}"
    TM->>TM: setViewport(state) → re-render rect

    Note over TC,TM: User brushes minimap
    TM->>TM: "handlePointerDown → dragMode=brush"
    TM->>TM: handlePointerMove → setBrushRange (visual only)
    TM->>TC: controller.zoomToRange(start, end) [on pointerUp]
    TC->>TC: commitViewport(newScale, newScrollLeft)
    TC-->>TM: subscriber notified → rect updates
Loading

Reviews (3): Last reviewed commit: "Merge branch 'main' into HDX-3951-add-tr..." | Re-trigger Greptile

Comment thread packages/app/src/components/TimelineChart/TimelineChart.tsx
Comment thread packages/app/src/components/TimelineChart/TimelineMinimap.tsx Outdated

@pulpdrew pulpdrew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great stuff

@kodiakhq kodiakhq Bot merged commit d1802e1 into main Jul 1, 2026
19 checks passed
@kodiakhq kodiakhq Bot deleted the HDX-3951-add-trace-minimap branch July 1, 2026 07:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automerge review/tier-3 Standard — full human review required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants