TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from "recharts";4import { formatNumber, formatPercent, titleCase } from "@/lib/format";5import { CHART_COLORS, NETWORK_COLORS } from "./chart-theme";6import { ChartTooltip } from "./chart-tooltip";78export interface NetworkSlice {9 network: string;10 requests: number;11 percent: number;12}1314const LIVE_NETWORKS = new Set(["residential"]);1516/**17 * Part-to-whole of resolved network classes. All four classes are listed (0 % rows included);18 * networks that are not live yet say so instead of pretending to have traffic.19 */20export function NetworkDonut({ data, size = 156 }: { data: NetworkSlice[]; size?: number }) {21 const nonZero = data.filter((d) => d.requests > 0);22 const total = data.reduce((a, d) => a + d.requests, 0);23 return (24 <div className="flex flex-col items-center gap-5 sm:flex-row sm:items-center">25 <div className="relative shrink-0" style={{ width: size, height: size }}>26 <ResponsiveContainer width="100%" height="100%">27 <PieChart margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>28 <Tooltip content={<ChartTooltip labelFormatter={(_l, p) => titleCase(String(p[0]?.name ?? ""))} valueFormatter={(v) => `${formatNumber(v)} req`} />} />29 <Pie30 data={nonZero.length ? nonZero : [{ network: "none", requests: 1, percent: 0 }]}31 dataKey="requests"32 nameKey="network"33 innerRadius={size / 2 - 22}34 outerRadius={size / 2 - 6}35 paddingAngle={nonZero.length > 1 ? 2 : 0}36 stroke={CHART_COLORS.surface}37 strokeWidth={2}38 isAnimationActive={false}39 cornerRadius={3}40 >41 {(nonZero.length ? nonZero : [{ network: "none" }]).map((d) => (42 <Cell key={d.network} fill={d.network === "none" ? "var(--bg-muted)" : NETWORK_COLORS[d.network] ?? CHART_COLORS.muted} />43 ))}44 </Pie>45 </PieChart>46 </ResponsiveContainer>47 <div className="pointer-events-none absolute inset-0 flex flex-col items-center justify-center">48 <span className="text-[18px] font-semibold leading-none tracking-tight tabular">{formatNumber(total)}</span>49 <span className="mt-1 text-[11px] text-fg-subtle">resolved</span>50 </div>51 </div>52 <ul className="w-full min-w-0 flex-1 divide-y divide-border text-[13px]">53 {data.map((d) => (54 <li key={d.network} className="flex items-center justify-between gap-3 py-2">55 <span className="flex items-center gap-2 text-fg-muted">56 <span aria-hidden className="inline-block size-2 rounded-[2px]" style={{ backgroundColor: NETWORK_COLORS[d.network] ?? CHART_COLORS.muted }} />57 <span className="text-fg">{d.network === "isp" ? "ISP" : titleCase(d.network)}</span>58 {!LIVE_NETWORKS.has(d.network) ? <span className="text-[11px] text-fg-subtle">coming soon</span> : null}59 </span>60 <span className="flex items-center gap-3 font-mono tabular">61 <span className="text-fg-subtle">{formatNumber(d.requests)}</span>62 <span className="w-12 text-right">{formatPercent(d.percent, d.percent > 0 && d.percent < 1 ? 1 : 0)}</span>63 </span>64 </li>65 ))}66 </ul>67 </div>68 );69}70