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
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export default function App() {

<div className="grid grid-cols-1 gap-3.5 lg:grid-cols-[1.9fr_1fr]">
<StalePanel reason={staleTraceDerived}>
<LatencyChart series={data.latencyP95} />
<LatencyChart series={data.latencyP95} sample={conn.status === 'sample'} />
</StalePanel>
<StalePanel reason={staleTraceDerived}>
<StatusMix traces={data.traces} />
Expand Down
30 changes: 30 additions & 0 deletions src/components/latency-chart.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,36 @@ describe('latency chart with no samples', () => {
})
})

describe('latency chart on sample data', () => {
afterEach(cleanup)

/**
* With no platform the console draws a generated curve. The top bar says SAMPLE
* DATA, but this header said "rolling window" — a claim about where the numbers
* came from that a generated curve cannot make. The header has to say it instead.
*/
it('says the curve is sample data, not a window', () => {
const { getByText, queryByText, getByRole } = render(<LatencyChart series={[34, 41, 38]} sample />)
expect(getByText(/sample data/)).toBeTruthy()
expect(queryByText(/rolling window/), 'a generated curve claimed to be a window').toBeNull()
expect(getByRole('img').getAttribute('aria-label')).toMatch(/sample data/)
})

it('still draws the curve, so the demo stays explorable', () => {
// Every other card shows sample values too; an empty chart beside them would
// single this one out without making the screen any more honest.
const { container } = render(<LatencyChart series={[34, 41, 38]} sample />)
expect(container.querySelector('polyline')).not.toBeNull()
})

it('drops the label once real samples replace it', () => {
const { getByText, queryByText, rerender } = render(<LatencyChart series={[34, 41, 38]} sample />)
rerender(<LatencyChart series={[12, 40]} />)
expect(getByText(/rolling window/)).toBeTruthy()
expect(queryByText(/sample data/)).toBeNull()
})
})

describe('status mix', () => {
afterEach(cleanup)

Expand Down
15 changes: 11 additions & 4 deletions src/components/latency-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ function niceTicks(max: number, count = 4): number[] {
*/
const EMPTY_SCALE_MAX = 100

/** Single-series p95 latency area with a crosshair+tooltip. One hue (telemetry), no legend needed. */
export function LatencyChart({ series }: { series: number[] }) {
/**
* Single-series p95 latency area with a crosshair+tooltip. One hue (telemetry), no legend needed.
*
* `sample` marks a series this console generated because no platform answered. The
* top bar already says SAMPLE DATA, but the chart is the one card whose header made
* a claim of its own — "rolling window" — and a generated curve is not a window onto
* anything. The header names what it is instead.
*/
export function LatencyChart({ series, sample = false }: { series: number[]; sample?: boolean }) {
const gradId = useId()
const svgRef = useRef<SVGSVGElement>(null)
const [hover, setHover] = useState<number | null>(null)
Expand Down Expand Up @@ -67,7 +74,7 @@ export function LatencyChart({ series }: { series: number[] }) {
<CardHeader className="flex items-baseline justify-between pb-2">
<CardTitle className="text-[13.5px] font-semibold">Latency p95 over time</CardTitle>
<span className="font-mono text-[11px] text-muted-foreground">
{empty ? 'ms · default scale' : 'ms · rolling window'}
{sample ? 'ms · sample data' : empty ? 'ms · default scale' : 'ms · rolling window'}
</span>
</CardHeader>
<div className="relative px-2.5">
Expand All @@ -77,7 +84,7 @@ export function LatencyChart({ series }: { series: number[] }) {
className="block h-[190px] w-full touch-none"
preserveAspectRatio="none"
role="img"
aria-label="p95 latency over the rolling window"
aria-label={sample ? 'p95 latency, generated sample data' : 'p95 latency over the rolling window'}
onPointerMove={onMove}
onPointerLeave={() => setHover(null)}
>
Expand Down
Loading