Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 4 additions & 13 deletions src/components/time-series-chart/chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
type LineWithColor,
} from "./scales";
import { YAxis, XAxis } from "./axis";
import { SeriesGradients, SeriesPaths, DowntimeBands, HoverMarkers, type DrawnLine } from "./series";
import { SeriesGradients, SeriesPaths, HoverMarkers, type DrawnLine } from "./series";
import { Legend } from "./legend";
import { Tooltip } from "./tooltip";

Expand All @@ -22,11 +22,6 @@
onZoom?: (next: { startFrac: number; endFrac: number } | null) => void;
onToggleExclude?: (slug: string) => void;
onResetExcluded?: () => void;
/** Only render the downtime bands + pill labels when the parent bench
* opted in (spec declared live_activity). Otherwise natural nulls in
* any bench's series24h would fire a "DATA MISSING" pill on charts
* that never asked for the feature (observed on rpc-reliability). */
showDowntime?: boolean;
};

export function Chart({
Expand All @@ -38,7 +33,6 @@
onZoom,
onToggleExclude,
onResetExcluded,
showDowntime = false,
}: ChartProps) {
const W = 1000;
const H = 360;
Expand Down Expand Up @@ -298,7 +292,7 @@
// line draws a break but the dot keeps rendering at 0 / NaN.
return { ...l, color, pts, linePath, fillPath, lastX, lastY, last, isGap };
});
}, [slicedLines, padL, padT, innerW, innerH, lo, yRange, expectedPoints]);

Check warning on line 295 in src/components/time-series-chart/chart.tsx

View workflow job for this annotation

GitHub Actions / check

React Hook useMemo has a missing dependency: 'zoom'. Either include it or remove the dependency array

// Hover line position: mirror the right-anchored placement used by drawn().
// hover.idx is in [0, numPoints-1]; we map it to the visible chart via the
Expand Down Expand Up @@ -392,12 +386,9 @@
{/* X tick labels */}
<XAxis xTicks={xTicks} padL={padL} padT={padT} innerW={innerW} innerH={innerH} />

{/* Downtime bands. Rendered before the lines so the stroke stays
on top of the highlight. Contiguous null-buckets (from spec
`unless changes == 0`) become visible red columns. */}
{showDowntime && <DowntimeBands drawn={drawn} padT={padT} innerH={innerH} />}

{/* Areas + lines */}
{/* Areas + lines. Gaps in the series render as natural breaks in
the stroke — no tinted band, no pill: the missing pixels are
the signal. */}
<SeriesPaths drawn={drawn} unit={unit} />

{/* Drag-to-zoom selection rect. Brushed window highlighted in
Expand Down
1 change: 0 additions & 1 deletion src/components/time-series-chart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,6 @@ export function TimeSeriesChart({
onZoom={setZoom}
onToggleExclude={toggle}
onResetExcluded={excluded.size > 0 ? reset : undefined}
showDowntime={benchmark.results.some((r) => r.liveStatus != null)}
/>
)}
</figure>
Expand Down
117 changes: 4 additions & 113 deletions src/components/time-series-chart/series.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,119 +16,10 @@ type SeriesPathsProps = {
unit: string;
};

type DowntimeBandsProps = {
drawn: DrawnLine[];
padT: number;
innerH: number;
};

/** Colored rectangles that highlight the exact window each line was
* silent (contiguous gap indices), plus a high-contrast pill label
* above each band naming the provider that dropped off. Pills stack
* vertically when multiple providers went silent at the same time so
* simultaneous outages read as separate lines instead of colliding
* as unreadable overlapping text. Rendered under SeriesPaths so the
* line stroke stays on top; skipped for excluded (legend-toggled)
* providers so their bands disappear with the line. */
export function DowntimeBands({ drawn, padT, innerH }: DowntimeBandsProps) {
// Collect every gap band across every visible provider. Labels used to
// be rendered on top of each band; they were removed because the pill
// often mislabelled the cause (harness reconnect vs real crash vs
// sample alignment artefact). The tinted band + dashed edges alone
// read as "no data here" without asserting a cause.
type Band = {
slug: string;
color: string;
x: number;
w: number;
};
const all: Band[] = [];
for (const d of drawn) {
if (d.excluded) continue;
// Only count gap runs that start AFTER the first observed sample.
// A leading run of nulls (Prom retention shorter than the visible
// window, harness started mid-range, or provider added recently)
// is "we didn't measure yet", not "provider was down for a week".
// Without this guard the 30D view on aggregator-head-lag rendered
// a chart-wide band during Prom's initial fill period.
let seenData = false;
let runStart: number | null = null;
const push = (endX: number) => {
if (runStart == null) return;
if (!seenData) {
runStart = null;
return;
}
const startX = d.pts[runStart].x;
all.push({
slug: d.slug,
color: d.color,
x: startX,
w: Math.max(6, endX - startX),
});
runStart = null;
};
for (let i = 0; i < d.pts.length; i++) {
const p = d.pts[i];
if (p.gap) {
if (runStart == null) runStart = i;
} else {
push(d.pts[i].x);
seenData = true;
}
}
// Trailing gap that runs to the current time — meaningful only
// when the series had prior data (same seenData guard).
if (runStart != null) push(d.pts[d.pts.length - 1].x);
}
if (all.length === 0) return null;

// Label pills were removed intentionally: the guard upstream can't
// always tell "aggregator crash" apart from "our harness reconnect"
// or "worker step misalignment on a 30 min silence in a 7 d view",
// and a mislabelled pill blames the wrong side. The tinted band +
// dashed edges alone read as "no data recorded here" without
// asserting a cause. When we have a first-party signal that a
// specific provider went down, a proper status badge will be added
// separately — the sparkline is not the place to assign blame.

return (
<g className="ts-downtime">
{all.map((b, i) => (
<g key={`band-${b.slug}-${i}`}>
<rect
x={b.x}
y={padT}
width={b.w}
height={innerH}
fill={b.color}
opacity={0.1}
/>
<line
x1={b.x}
x2={b.x}
y1={padT}
y2={padT + innerH}
stroke={b.color}
strokeWidth={0.8}
strokeDasharray="3 3"
opacity={0.55}
/>
<line
x1={b.x + b.w}
x2={b.x + b.w}
y1={padT}
y2={padT + innerH}
stroke={b.color}
strokeWidth={0.8}
strokeDasharray="3 3"
opacity={0.55}
/>
</g>
))}
</g>
);
}
// DowntimeBands was removed: tinted bands + pill labels were misleading
// (mislabelled provider, alignment artefacts). Gaps in the series line
// now speak for themselves — SeriesPaths renders a natural break wherever
// the underlying values are null.

export function SeriesPaths({ drawn, unit }: SeriesPathsProps) {
return (
Expand Down
Loading