Freshness, of the data Most freshness indicators report on the page, not the data. A refresh that succeeds against a stalled pipeline produces a confidently current-looking screen full of old numbers. Tokens this needs: --foreground, --muted, --muted-foreground, --border, --status-warn, --state-live, --state-stale, --status-critical, --status-unknown The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // FreshnessIndicator.tsx ──────────────────────────────────────────────────────────────────────── import { freshness, FRESHNESS_COLOR } from "./freshness"; /** Prometheus's default lookback: an instant query returns the newest sample * younger than this, so anything inside it draws as if it were current. */ const LOOKBACK_MS = 5 * 60_000; const ago = (ms: number) => { const s = Math.round(ms / 1000); if (s < 60) return `${s}s ago`; const m = Math.round(s / 60); return m < 60 ? `${m}m ago` : `${Math.floor(m / 60)}h ${m % 60}m ago`; }; /** * Three ages on one axis. The page's own refresh is reported, but it is the * last of the three, because a query that succeeds against a stalled pipeline * is not news about the data. The state comes from when the newest sample * arrived against the cadence it was expected at. */ export function FreshnessIndicator({ lastArrival, expectedEveryMs, lastQuery, covers, lookbackMs = LOOKBACK_MS, now, width = 640 }: { /** When the newest sample arrived. Null when nothing has ever arrived. */ lastArrival: Date | null; expectedEveryMs: number; /** When the page last ran its queries. Not the data's age. */ lastQuery: Date; /** The span the value summarises, which is neither of the other two. */ covers: { from: Date; to: Date }; lookbackMs?: number; /** The clock to age against. Pass one to render on a server. */ now?: Date; width?: number; }) { const clock = now ?? new Date(); const { state, ageMs } = freshness(lastArrival, expectedEveryMs, clock); const color = FRESHNESS_COLOR[state]; // The axis runs from the start of the covered window to now. const span = clock.getTime() - covers.from.getTime(); const x = (d: Date) => 80 + ((d.getTime() - covers.from.getTime()) / span) * (width - 100); const minutesBefore = (d: Date) => Math.round((clock.getTime() - d.getTime()) / 60_000); const mid = new Date(covers.from.getTime() + span / 2); const lookbackStart = new Date(clock.getTime() - lookbackMs); return (
{lastArrival ? `last sample arrived, ${ago(ageMs!)}` : "no sample has arrived"} · {state}