feat(web): migrate charts to TanStack Charts#131

open7
test/e2e-baseline
feat/tanstack-charts
opened18d agobyOoliver
View on GitHubTwo-way sync enabledPR last imported 3h ago

Note

🤖 GPT-6.1-Sol on behalf of Oliver

Round 3 review fixes

Restore original midnight/noon/date boundaries, 45-degree desktop time labels and horizontal numeric labels. Two pixel-bounded grid paths preserve bucket boundaries without one DOM node per bucket. Restore 3px traffic/router outlines, 2px file analysis lines, filled purple spectrum points, reference/error-bar opacity, numeric endpoint ticks and legend glyphs that match their marks. Lower-layer adaptation uses the existing Svelte host and literal palette; later layers retain these fixes.

Own-tip verification: format, lint, typecheck, production build, 230 web tests and 71 Playwright tests passed. Human review: compare short/week/long time axes, numeric file plots, legend toggles and compact labels in both themes. The public sheet compares illustrative fixture charts before round 3 and at the combined stack tip. Full v5 Chart.js comparison sheets remain private/local.

All dashboard charts and file spectrum/structure plots now render through the official @tanstack/charts/svelte adapter, pinned to 1.0.0. Chart.js, its annotation plugin, and the old renderer adapters are removed. Series, metric units, stacking, partial/unknown coverage, annotations, legend toggles, crosshairs, bucket drilldown, time-range selection, themes, resizing, and deferred card activation retain their existing behavior.

Layer 3 of the stack, based on #130, following #129. No merge or Cloudflare deployment. Only the isolated perf stage on :8090 was redeployed; the production test stage on :8080 was not touched.

Adapter and renderer decisions

The shipped Svelte adapter supports Svelte 5 runes, SSR markup and hydration under this SvelteKit 3 setup. Use it directly through the shared ChartPlot component. Application DOM subscriptions and sizing use attachments; definitions, data, loading and empty state remain derived.

Every chart uses SVG: traffic line/stacked area, characteristic panels, unique ports, IP/protocol breakdown, dimensions, dashboard spectrum, coverage lanes, file spectrum and file structure function. Comparing the same native dot mark and quantitative f(alpha) scale on real v5 points favored SVG at every measured size. At 9,870 marks, median render/presentation was 139/219 ms for SVG versus 398/436 ms for canvas. At 50,000 marks, render time was 808 ms versus 6,581 ms. Canvas reduced DOM nodes from about 50,000 to 51 but its CPU cost was worse, so it is not shipped.

Composed TanStack area/line/dot/rect marks implement the existing cumulative stacking, dashed partial segments, unknown gaps, hollow singleton/partial points, coverage lanes, f(alpha)=alpha reference line, and standard-deviation bars with caps. Decorative marks do not become tooltip or summary observations. Shared DOM overlays mirror crosshairs and selection across charts; pointer clicks retain nearest-bucket behavior throughout the plot. Native keyboard exploration and legend buttons are complemented by Shift+Arrow range selection and Enter/Escape commit/cancel.

Contract and fixes

The existing chart-surface/render-state/series/axis/tooltip, card lifecycle, normalized interaction targets, and activation/sentinel contract is preserved. Summaries come from finite positioned scene points after rendering. A small attribute observer keeps the publisher's readiness and accessibility attributes through SVG reconciliation and disconnects on teardown.

Resolved baseline findings F01, F02, F10, and the chart-rendering portion of F05: totals use the hovered bucket identity rather than a trimmed index; empty selections explain themselves; singleton domains are padded; legends, value exploration, drilldown and range selection have keyboard equivalents. External findings.md records each resolution. Remaining native card reorder/resize gestures are tracked separately as F11 for redesign.

No baseline e2e assertion was weakened or changed. Five new regressions cover hovered totals, daily singleton characteristics/ports, keyboard legend/value/drilldown, keyboard range cancellation/application, and a 20,001-point spectrum with one accessible interaction target. Unit tests that mocked Chart.js pixel conversion were replaced with bucket-identity checks; the old per-point styling arrays were replaced with coverage-segment tests that assert gaps and partial adjacency.

Performance before and after

Same v5 dataset, June 1 2025 through October 6 2026, five API runs, three fresh browser contexts per page, one discarded API warmup, no throttling, one-second settling and explicit GC. The readiness selector is [data-chart-rendered="true"] because SSR SVG exists before interactive rendering. Layer 1 remains the before baseline; layer 2 hook overhead was not measured separately. Three browser samples have substantial sampling limits, and all-chart timing includes scrolling/settling/GC.

MetricBeforeAfter
Total JS, raw / gzip KiB711.6 / 228.1631.6 / 202.4
Dashboard with static dependencies, raw / gzip KiB682.3 / 208.4641.6 / 195.6
Total CSS, raw / gzip KiB60.8 / 10.561.0 / 10.5
Default dashboard FCP / LCP p50 ms136 / 136120 / 120
Default visible charts p50 / p95 ms509.1 / 642.6569.3 / 571.4
Default all charts p50 ms3258.94271.3
Default initial observed TBT p50 ms130159
Default heap before / after GC MiB31.3 / 18.339.2 / 29.9
Six-month visible / all charts p50 ms456.3 / 2722.8489.6 / 3183.8
Filtered-hourly visible / all charts p50 ms400.3 / 2691.2435.1 / 3205.1
File detail LCP / chart readiness p50 ms744 / 729.7684 / 673.3
File initial observed TBT p50 ms411336
File heap after GC MiB14.68.1
Default traffic API p50 / p95 ms30.0 / 35.237.3 / 37.9
Default spectrum API p50 / p95 ms61.9 / 87.276.0 / 90.6
Default structure API p50 / p95 ms102.5 / 110.7116.3 / 133.7

Bundles and file rendering improve, while dashboard readiness and retained heap regress. Large SVG scenes, point/focus metadata and scene publication should be profiled in layer 4. This PR changes no queries; API timing differences do not demonstrate an API improvement. Spectrum/structure response bodies remain 2,969.7/4,882.4 KiB.

Final reports and renderer samples are in /tmp/atlantis-frontend-overhaul/perf/layer3/. The fresh bundle export is final-build; earlier merged-directory total bundle inventories are invalid and explicitly labeled in measurement-notes.md. Future exports must use a fresh destination because Docker copy retains old hashed chunks.

Verification and human review guide

Automated: bun run format, bun run lint, bun run typecheck, bun run test:web with 215 tests, and bun run test:e2e with 62 tests passed. The architecture documentation formatter check passed. The final benchmark completed all 35 query cases and 18 browser loads with zero errors.

Implementation browser pass: 24 checks across all eight dashboard cards and all 12 file-analysis charts on real read-only v5, including hover, legends, keyboard actions, brush/drilldown, both themes, empty recovery and 390px layouts. Saved 49 private after-screenshots locally in e2e/layer3-screens/; they were not uploaded or committed. T3 preview could not reach pinot's loopback port, so this pass used the repository's requested Playwright workflow. The v5 file metadata stayed unchanged and perf's bind mount is read-only.

For human review:

  • Open :8090 with the default uoregon window, scroll through all eight cards, and verify deferred activation, axes/units, responsive resizing and both themes.
  • Switch traffic line/stacked modes, metrics and family; hide/restore legend entries. On the isolated March 1 fixture at 5-minute grouping, the first tooltip must show TCP 100 and Total Flows 160.
  • Inspect partial capture boundaries. Partial observations retain hollow markers/dashed segments; unknown observations remain gaps; known zero remains plotted.
  • Focus a chart and use arrows/Home/End, then Enter to open a bucket. Shift+Arrow then Enter must apply a range; Escape must cancel. Pointer brush and whole-plot clicks should preserve the existing URL/grouping and file context.
  • Open a populated v5 file and inspect every source/destination spectrum reference line and structure-function SD bar. Recheck MAAD family/measure changes and narrow layouts.
  • Review the all-SVG tradeoff and dashboard timing/heap regressions. The separate extensive QA pass is still pending. Native card layout gestures, selection persistence, narrow file text, date validation, file titles and duplicate summary requests remain later-layer work; full screen-reader, real touch, Firefox and WebKit checks are not claimed.

Changes made by GPT-6.1-Sol through the Codex harness in T3 Code.

Before and after: calendar ticks, stroke weights, filled points and legend glyphs on generated public fixtures

Checks

All checks passed

Added 5 commits

  • test(web): cover chart totals, singleton marks, and keyboard interactions5dee3f8
  • docs(web): document the TanStack chart renderer7392db4
  • feat(web): migrate dashboard and file charts to TanStack Chartsca9dc6d
  • fix(web): preserve chart space and labels under dense legends43c35e1
  • test(web): verify chart stacking and traffic request cancellation10bf5ab

Independent layer-3 QA completed against the read-only perf stage on :8090.

Found and fixed two migration regressions:

  • S2: Dense native legends collapsed the 390px IP plot to almost zero height and crowded ports/protocol charts. Capped the legend height, retained scrollable 44px native buttons, and update contract targets when scrolling.
  • S3: Rotated temporal ticks pushed the Time axis title below the clipped card. Added enough bottom margin for the displayed label.

Fix: 43c35e1. Additional coverage: 10bf5ab.

Six new fixture-backed Playwright tests cover dense legend/axis behavior at 390/768/1280/1920px, actual scrolled legend targets and pointer/keyboard restoration, cumulative stacking proportions after legend changes, and obsolete traffic-request cancellation. They use the chart contract and real DOM bounds rather than pixels or private data.

The browser audit covered every listed flow, all eight dashboard cards and 12 file charts, all granularities and seven-chart drilldown, brush and URL/history, every metric/family/side/source control, light/dark themes, all requested widths, single/empty/error recovery, rapid filter changes, accessibility-tree and keyboard basics, and repeated-filter heap/listener probes. Compared all baseline card captures with SVG results and matched count/min/max/total for 40 rendered series against captured API data. No incorrect metric or stale-render overwrite was confirmed. Expected injected 503 and invalid-route errors were separated from application errors; there were no unexpected page exceptions.

All required checks passed: bun run format, bun run lint, bun run typecheck, bun run test:web with 215 tests, and bun run test:e2e with 68 tests.

Human review guide: Open the populated single-day, five-minute dashboard on perf at 390px. Scroll to IP counts and ports, scroll through the legend, toggle the last series with mouse and Space, then inspect the visible Time title. Compare 768/1280/1920px and both themes. Check traffic stack order before/after hiding TCP, hover its original bucket and exercise brush/reset. These real-stage checks have passed; Firefox/WebKit, real touch devices and a full screen-reader session remain unverified.

Layer 4 remains responsible for the already documented default-dashboard render/heap regression and duplicate initial file-summary requests. Thirty repeated direction changes showed stable listener counts and two stable DOM sizes, with GC heap around 28–31MiB, rather than confirmed unbounded growth. No new controlled perf/bundle benchmark was run. The inherited selection-persistence, narrow-file layout, calendar/date-order validation, file-title and keyboard card-layout findings remain documented for their existing later-layer scope.

Redeployed only perf using its isolated environment. Final image atlantis-perf-web:50283d58b7cabdc5f1d02ed457eb0625 is healthy with /data read-only; the source DB stat is unchanged. No actions targeted :8080/test or Cloudflare.

The full private QA report is /tmp/atlantis-frontend-overhaul/e2e/layer3-qa.md; 297 before/fixed screenshots are in e2e/layer3-qa-screens/. No private data or screenshots were uploaded or committed. LOG.md has a QA handoff entry.

Added 2 commits

  • fix(web): restore calendar ticks and grid boundaries5fc7aab
  • fix(web): restore chart strokes points and legend glyphsab5316e