spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1'use client';23import { AnimatedNumber } from '@/components/ui/AnimatedNumber';4import { fmt } from '@/lib/format';5import { useDegraded, useLive } from '@/lib/live';6import { Time } from '@/lib/time';7import type { Ticker as TickerT } from '@/lib/types';89interface Cell {10 key: keyof TickerT;11 label: string;12 digits?: number;13 unit?: string;14 color?: (t: TickerT) => string | undefined;15}16const CELLS: Cell[] = [17 { key: 'bgp_updates_per_s', label: 'BGP updates/s', digits: 1 },18 { key: 'bgp_withdrawals_per_s', label: 'withdrawals/s', digits: 1, color: (t) => (t.bgp_withdrawals_per_s > 30 ? 'var(--p-stressed)' : undefined) },19 { key: 'probes_active', label: 'probes active', digits: 0, color: (t) => (t.probes_active < t.probes_total ? 'var(--warn)' : undefined) },20 { key: 'measurements_per_s', label: 'measurements/s', digits: 1 },21 { key: 'targets_degraded', label: 'targets degraded', digits: 0, color: (t) => (t.targets_degraded > 0 ? 'var(--p-elevated)' : undefined) },22 { key: 'regions_elevated', label: 'regions elevated', digits: 0, color: (t) => (t.regions_elevated > 0 ? 'var(--p-elevated)' : undefined) },23 { key: 'regions_severe', label: 'regions severe', digits: 0, color: (t) => (t.regions_severe > 0 ? 'var(--p-severe)' : undefined) },24 { key: 'dns_failures_per_min', label: 'DNS failures/min', digits: 0 },25 { key: 'median_global_rtt_ms', label: 'median RTT', digits: 1, unit: 'ms' },26 { key: 'route_changes_per_min', label: 'route changes/min', digits: 1 },27 { key: 'active_incidents', label: 'active incidents', digits: 0, color: (t) => (t.active_incidents > 0 ? 'var(--p-high)' : undefined) },28 { key: 'bgp_updates_per_min', label: 'BGP updates/min', digits: 0 },29];3031/** Live ticker — a dense grid that updates in place (no marquee). Every value is a real counter (spec §66). */32export function Ticker({ initial }: { initial: TickerT | null }) {33 const live = useLive((s) => s.ticker);34 const updates = useLive((s) => s.updates);35 const { degraded } = useDegraded();36 const t = live ?? initial;37 if (!t) return <p className="text-xs text-ink-3">Ticker unavailable.</p>;38 return (39 <div className={degraded ? 'opacity-50 saturate-50' : ''}>40 <dl className="grid grid-cols-2 gap-px overflow-hidden rounded-[4px] border border-line bg-line sm:grid-cols-3 lg:grid-cols-6">41 {CELLS.map((c) => {42 const v = t[c.key] as number;43 return (44 <div key={c.key} className="bg-panel px-3 py-2.5">45 <dt className="label truncate">{c.label}</dt>46 <dd className="num mt-0.5 text-[20px] leading-none" style={{ color: c.color?.(t) ?? 'var(--ink)' }}>47 <AnimatedNumber value={v} digits={c.digits ?? 1} duration={updates ? 500 : 0} />48 {c.unit && <span className="ml-1 text-[11px] text-ink-3">{c.unit}</span>}49 {c.key === 'probes_active' && <span className="text-[12px] text-ink-3">/{fmt(t.probes_total, 0)}</span>}50 {c.key === 'targets_degraded' && <span className="text-[12px] text-ink-3">/{fmt(t.targets_total, 0)}</span>}51 </dd>52 </div>53 );54 })}55 </dl>56 <p className="num mt-1.5 text-[10.5px] text-ink-3">57 counters at <Time ts={t.ts} style="time" /> · {fmt(t.regions_normal, 0)} regions normal58 </p>59 </div>60 );61}62