Drill-down Getting from the number that is wrong to the rows that made it wrong. The breadcrumb is the load-bearing part, because a reader three levels in has usually forgotten what the filter above them was. npx shadcn@latest add breadcrumb Tokens this needs: --card, --card-foreground, --accent, --accent-foreground, --muted-foreground, --border, --chart-1 ──────────────────────────────────────────────────────────────────────── // DrillDown.tsx ──────────────────────────────────────────────────────────────────────── import { Fragment, useState } from "react"; import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from "@/components/ui/breadcrumb"; import { cn } from "@/lib/utils"; /** Every aggregate is a door. A node with children opens the narrower view * of the same thing; a node without them is the bottom, and the level says so. */ export type Node = { name: string; value: number; children?: Node[]; }; /** What has to survive the click. The window and the cluster travel with * every level, and the value under the cursor arrives as a chip. */ export type Scope = { cluster: string; from: Date; to: Date }; type Props = { root: Node; scope: Scope; /** Names from the root down to the level to open on. Put it in the URL, so * back returns to the exact prior state. */ defaultPath?: string[]; onNavigate?: (path: string[]) => void; }; const hhmm = (d: Date) => d.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit", timeZone: "UTC" }); const span = (s: Scope) => `${Math.round((s.to.getTime() - s.from.getTime()) / 3_600_000)}h`; const n = (v: number) => v.toLocaleString("en-US"); export function DrillDown({ root, scope, defaultPath = [], onNavigate }: Props) { const [path, setPath] = useState(defaultPath); const go = (next: string[]) => { setPath(next); onNavigate?.(next); }; // Walk the path to the current node, keeping every ancestor for the crumbs. const trail = path.reduce((acc, name) => { const child = acc[acc.length - 1].children?.find((c) => c.name === name); return child ? [...acc, child] : acc; }, [root]); const here = trail[trail.length - 1]; const rows = here.children ?? []; const max = Math.max(...rows.map((r) => r.value), 1); const bottom = rows.every((r) => !r.children); const rootLabel = `${root.name} · ${scope.cluster} · ${span(scope)}`; return (
{trail.map((node, i) => { const last = i === trail.length - 1; const label = i === 0 ? rootLabel : node.name; return ( {last ? ( {label} ) : ( )} {!last && } ); })} {/* The scope arrived with the click. Cluster, window, and the number the viewer was chasing, so it is visibly still here. */}
{[scope.cluster, `${hhmm(scope.from)}-${hhmm(scope.to)}`, n(here.value)].map((chip) => ( {chip} ))}
    {rows.map((r) => { const door = !!r.children; const Tag = door ? "button" : "div"; return (
  1. go([...path, r.name]) : undefined} className={cn("grid w-full grid-cols-[minmax(0,1fr)_120px_56px] items-center gap-3 rounded px-1 py-0.5 text-left text-xs", door && "hover:bg-accent hover:text-accent-foreground")} > {r.name} {n(r.value)}
  2. ); })}
{bottom &&

Bottom of the hierarchy. Nothing here opens further.

}
); } ──────────────────────────────────────────────────────────────────────── // demo.tsx ──────────────────────────────────────────────────────────────────────── import { DrillDown, type Node } from "./DrillDown"; /** * Errors in eu-west over one hour, by class, then by endpoint. The demo lands * one level down, on the TimeoutError bar that was clicked, with the cluster, * the window and the 4,182 still attached. The crumb goes back up; the * endpoints are the bottom and say so. */ const ERRORS: Node = { name: "Errors", value: 8_582, children: [ { name: "TimeoutError", value: 4_182, children: [ { name: "POST /checkout", value: 2_310 }, { name: "GET /cart", value: 1_104 }, { name: "POST /payments/authorize", value: 512 }, { name: "GET /search", value: 256 }, ], }, { name: "ConnectionReset", value: 1_960, children: [{ name: "GET /cart", value: 1_402 }, { name: "GET /search", value: 558 }] }, { name: "UpstreamUnavailable", value: 1_410, children: [{ name: "POST /payments/authorize", value: 1_410 }] }, { name: "RateLimited", value: 720, children: [{ name: "GET /search", value: 720 }] }, { name: "Other", value: 310, children: [{ name: "GET /health", value: 310 }] }, ], }; export default function Demo() { return (
); }