TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import { Bar, BarChart, CartesianGrid, Cell, LabelList, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts";4import { AXIS_TICK, CHART_COLORS } from "./chart-theme";5import { ChartTooltip } from "./chart-tooltip";67export type HorizontalBarFormat = "number" | "percent" | "ms" | "usd";89const FORMATTERS: Record<HorizontalBarFormat, (v: number) => string> = {10 number: (v) => v.toLocaleString("en-US"),11 percent: (v) => `${v.toFixed(1)}%`,12 ms: (v) => (v < 1000 ? `${Math.round(v)} ms` : `${(v / 1000).toFixed(2)} s`),13 usd: (v) => (v < 0.01 && v > 0 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`),14};1516export interface HorizontalBarDatum {17 label: string;18 value: number;19 /** Optional per-entity color (defaults to accent). */20 color?: string;21 /** Optional secondary text shown in the tooltip (e.g. request count). */22 hint?: string;23}2425/**26 * Single-series horizontal bars (one color for all bars unless the entity has a fixed color).27 * Used for success rate by network and error-code breakdowns.28 */29export function HorizontalBarChart({30 data,31 color = CHART_COLORS.accent,32 max,33 format = "number",34 rowHeight = 34,35 labelWidth = 120,36}: {37 data: HorizontalBarDatum[];38 color?: string;39 max?: number;40 /** Serializable formatter key (server components cannot pass functions to client components). */41 format?: HorizontalBarFormat;42 rowHeight?: number;43 labelWidth?: number;44}) {45 const valueFormatter = FORMATTERS[format];46 const height = Math.max(rowHeight * Math.max(data.length, 1) + 16, 80);47 return (48 <ResponsiveContainer width="100%" height={height}>49 <BarChart data={data} layout="vertical" margin={{ top: 4, right: 56, bottom: 4, left: 0 }} barCategoryGap="28%">50 <CartesianGrid horizontal={false} stroke={CHART_COLORS.grid} />51 <XAxis type="number" hide domain={[0, max ?? "auto"]} />52 <YAxis type="category" dataKey="label" width={labelWidth} tick={{ ...AXIS_TICK, fill: "var(--fg-muted)", fontSize: 12 }} axisLine={false} tickLine={false} interval={0} />53 <Tooltip54 cursor={{ fill: CHART_COLORS.cursor, opacity: 0.6 }}55 content={56 <ChartTooltip57 labelFormatter={(l) => String(l)}58 valueFormatter={(v) => valueFormatter(v)}59 names={{ value: "Value" }}60 footer={(p) => {61 const hint = (p[0]?.payload as HorizontalBarDatum | undefined)?.hint;62 return hint ? <span>{hint}</span> : null;63 }}64 />65 }66 />67 <Bar dataKey="value" radius={[0, 3, 3, 0]} maxBarSize={18} isAnimationActive={false} background={{ fill: "var(--bg-muted)", radius: 3 }}>68 {data.map((d) => (69 <Cell key={d.label} fill={d.color ?? color} />70 ))}71 <LabelList dataKey="value" position="right" formatter={(v: unknown) => valueFormatter(Number(v))} style={{ fill: "var(--fg-muted)", fontSize: 11.5, fontFamily: "var(--font-mono)" }} />72 </Bar>73 </BarChart>74 </ResponsiveContainer>75 );76}77