SPB Git forge
15commits 1branches 0releases
29.7 MBsize
maindefault branch
10 days agolast push
TypeScript 36.3% Python 31.8% Go 18% JavaScript 9.8% Shell 1.9% SQL 1.4% CSS 0.5%
3.3 KB · 62 lines tsx
Raw Blame History
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