feat: compare the targets side by side on the statistics page - #38
Merged
Conversation
The chips only ever narrowed the pages to one target; the payoff of having several is seeing them against each other. A tenth, full-width card on the statistics page holds a per-target summary table - average speeds, latency and failure rate, each dot wearing its chip's colour - and opens into an overlay of the targets' series with a metric switcher, one line per target. Client-only, and lazy on purpose: the per-target statistics are fetched when the card is first opened, cached against the exact query they answer for, and never while collapsed - N requests per range change would spend the fixed-window rate budget the page's own request lives on, and a 429 there blanks the whole page. The cache is handed to every render only while its key matches, so the Back button under an open panel shows a loading line rather than the previous range's series, and the fetch keeps its own generation counter so it can never strand the page's stale guard. The overlay keeps each series on its own instants - the x axis is linear epoch time - and interacts by nearest point, since index mode assumes one shared label array; the tooltip titles from the point's own parsed x. The colour cycle gains one home: targetSeriesToken carries the normalisation, targetColour derives from it, and the canvas resolves the same token through the chart theme, so a line and its dot cannot disagree. Marker density follows the drawn total while tension follows the longest series - one count for both drew the same data two ways. The table separates a fetch that failed from a target that measured nothing, and the six new strings ship translated in all 23 locales. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📋 Description
The payoff the target chips only filtered towards: a tenth, full-width card on the statistics page that puts the targets side by side. Collapsed it is a per-target summary table — average download/upload/ping and failure rate, each row's dot in its chip's colour — and expanded it adds an overlaid chart of the targets' series with a Download/Upload/Ping switcher, one line per target, plus the table.
Lazy by design. The per-target statistics are fetched only when the card is first opened and cached against the exact query+node+targets key they answer for: N requests per range change would spend the same fixed-window rate budget the page's own request lives on, and a 429 there blanks the whole page. The cache is handed to renders only while its key matches, so a Back-button range change under the open panel shows a loading line rather than the previous range's series, and the fetch keeps its own generation counter so it can never strand the page's stale-response guard.
Honest overlay. Each target keeps its own instants on the linear time axis (resampling onto a merged timeline would shred every line into dashes under the deliberate spanGaps-off rule); interaction is nearest-point with the tooltip titled from the point's own timestamp, no failed-test branch and no legend filter (a target may literally be named "Failed test"). Marker density follows the total drawn points while curve tension follows the longest series. The colour cycle gains one home —
targetSeriesToken— so a line and its chip dot cannot disagree, androundIndexById's-1still resolves.The table separates a fetch that failed ("Couldn't load") from a target that measured nothing (honest N/A). The reflow suite models the tenth card rather than being routed around (cards list, spanning model, wide-class rules restated per stage), the new chart joined the palette and point-density guard lists, and the six new strings ship translated in all 23 locales.
Suites:
npm testand the integration suite green, lint 0 errors,vite buildclean. Design went through an adversarial review round (9 defects fixed pre-implementation, incl. the rate-budget and tooltip-index-mode traps).🚀 Changes made to ...
✅ Checklist
en.jsonis edited here)🤖 Generated with Claude Code