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 Link from 'next/link';4import { useEffect, useState } from 'react';5import { Bar } from '@/components/ui/primitives';6import { fmt, fmtDelta, fmtInt } from '@/lib/format';7import { COMPONENT_LABEL, pressureColor } from '@/lib/pressure';8import { Time } from '@/lib/time';9import type { Explain, GlobalPressure } from '@/lib/types';1011function scopeHref(scopeType: string, scopeId: string | null): string | null {12 if (!scopeId) return null;13 if (scopeType === 'region') return `/internet/${scopeId}`;14 if (scopeType === 'country') return `/country/${scopeId.toLowerCase()}`;15 if (scopeType === 'asn') return `/asn/${scopeId}`;16 if (scopeType === 'service') return `/service/${scopeId}`;17 if (scopeType === 'bgp') return '/bgp';18 return null;19}2021/** "Why is Global Pressure 42.7?" — explain rows, then components → signals from /api/v1/explain. */22export function ExplainPanel({ global, onClose }: { global: GlobalPressure; onClose: () => void }) {23 const [deep, setDeep] = useState<Explain | null>(null);24 const [err, setErr] = useState<string | null>(null);25 const [openComp, setOpenComp] = useState<string | null>(null);2627 useEffect(() => {28 const onKey = (e: KeyboardEvent) => e.key === 'Escape' && onClose();29 window.addEventListener('keydown', onKey);30 document.body.style.overflow = 'hidden';31 fetch('/api/v1/explain')32 .then((r) => (r.ok ? r.json() : Promise.reject(new Error(String(r.status)))))33 .then((d: Explain) => setDeep(d))34 .catch(() => setErr('Deep explanation unavailable'));35 return () => {36 window.removeEventListener('keydown', onKey);37 document.body.style.overflow = '';38 };39 }, [onClose]);4041 return (42 <div className="fixed inset-0 z-[90] flex justify-end bg-bg/70" onClick={onClose} role="presentation">43 <aside role="dialog" aria-modal="true" aria-labelledby="explain-title" className="flex h-full w-full max-w-[640px] flex-col border-l border-line bg-panel" onClick={(e) => e.stopPropagation()}>44 <header className="flex items-start justify-between gap-4 border-b border-line px-5 py-4">45 <div>46 <p className="label">Explain</p>47 <h2 id="explain-title" className="mt-1 text-[17px] font-medium">48 Why is Global Pressure <span className="num" style={{ color: pressureColor(global.level) }}>{fmt(global.pressure)}</span>?49 </h2>50 <p className="mt-1 text-[11.5px] text-ink-2">51 Engine cycle <Time ts={global.ts} style="time" className="num" /> · confidence {Math.round(global.confidence * 100)} %52 </p>53 </div>54 <button type="button" onClick={onClose} className="rounded-[3px] border border-line px-2 py-1 text-xs text-ink-2 hover:text-ink" aria-label="Close">55 esc56 </button>57 </header>5859 <div className="flex-1 overflow-y-auto px-5 py-4">60 <p className="label mb-2">Contributions</p>61 <ul className="divide-y divide-line">62 {global.explain.map((row, i) => {63 const href = scopeHref(row.scope_type, row.scope_id);64 return (65 <li key={i} className="flex items-baseline gap-3 py-2 text-[13px]">66 <span className="num w-14 shrink-0 text-right" style={{ color: row.points >= 0 ? pressureColor(Math.min(100, 30 + row.points * 3)) : 'var(--p-calm)' }}>67 {fmtDelta(row.points)}68 </span>69 <span className="flex-1 text-ink">{row.text.replace(/^[+−-]\s?[\d.]+\s?(points?)?\s?(from|because)?\s?/i, (m) => (m.trim().endsWith('because') ? 'Because ' : ''))}</span>70 <span className="label shrink-0">{COMPONENT_LABEL[row.component] ?? row.component}</span>71 {href && (72 <Link href={href} className="shrink-0 text-xs text-accent hover:underline" onClick={onClose}>73 open →74 </Link>75 )}76 </li>77 );78 })}79 </ul>8081 <p className="label mb-2 mt-6">Components → signals</p>82 {err && <p className="text-xs text-warn">{err}</p>}83 {!deep && !err && <p className="text-xs text-ink-3">Loading signal breakdown…</p>}84 {deep && (85 <ul className="divide-y divide-line">86 {deep.components.map((c) => {87 const isOpen = openComp === c.id;88 return (89 <li key={c.id}>90 <button type="button" onClick={() => setOpenComp(isOpen ? null : c.id)} className="grid w-full grid-cols-[1fr_auto_auto_auto] items-center gap-3 py-2 text-left text-[13px]" aria-expanded={isOpen}>91 <span className="text-ink">92 <span className="mr-2 inline-block w-3 text-ink-3">{isOpen ? '−' : '+'}</span>93 {COMPONENT_LABEL[c.id] ?? c.id}94 </span>95 <span className="num text-right" style={{ color: pressureColor(c.score) }}>96 {fmt(c.score)}97 </span>98 <span className="num text-right text-ink-3">× {fmt(c.weight, 2)}</span>99 <span className="num w-12 text-right text-ink">{fmtDelta(c.contribution)}</span>100 </button>101 {isOpen && (102 <table className="tbl mb-3">103 <thead>104 <tr>105 <th>Signal</th>106 <th>Scope</th>107 <th className="r">Current</th>108 <th className="r">Median</th>109 <th className="r">MAD</th>110 <th className="r">z</th>111 <th className="r">n</th>112 <th className="r">Stress</th>113 <th className="r">Pts</th>114 </tr>115 </thead>116 <tbody>117 {c.signals.map((s) => (118 <tr key={`${s.signal_id}-${s.scope_id}`}>119 <td className="max-w-[200px] truncate text-ink" title={s.label}>120 {s.label}121 </td>122 <td className="text-ink-2">{s.scope_id ? `${s.scope_type}:${s.scope_id}` : s.scope_type}</td>123 <td className="num r">{fmt(s.current, s.current < 1 ? 3 : 1)}</td>124 <td className="num r text-ink-2">{fmt(s.baseline_median, s.baseline_median < 1 ? 3 : 1)}</td>125 <td className="num r text-ink-2">{fmt(s.mad, s.mad < 1 ? 3 : 1)}</td>126 <td className="num r" style={{ color: Math.abs(s.robust_z) >= 3 ? 'var(--p-high)' : 'var(--ink)' }}>127 {fmt(s.robust_z)}128 </td>129 <td className="num r text-ink-2">{fmtInt(s.samples)}</td>130 <td className="r">131 <Bar value={s.stress * 100} className="inline-block w-10 align-middle" />132 </td>133 <td className="num r">{fmtDelta(s.contribution)}</td>134 </tr>135 ))}136 </tbody>137 </table>138 )}139 </li>140 );141 })}142 </ul>143 )}144 {deep?.notes?.length ? (145 <ul className="mt-5 space-y-1 text-[11.5px] text-ink-3">146 {deep.notes.map((n, i) => (147 <li key={i}>· {n}</li>148 ))}149 </ul>150 ) : null}151 {deep?.excluded_probes?.length ? <p className="mt-3 text-[11.5px] text-warn">Excluded probes (self-exclusion): {deep.excluded_probes.join(', ')}</p> : null}152 </div>153 <footer className="border-t border-line px-5 py-3 text-[11.5px] text-ink-3">154 Composite observability index, not scientific truth. Weights and thresholds in{' '}155 <Link href="/methodology" className="text-accent hover:underline" onClick={onClose}>156 Methodology157 </Link>158 .159 </footer>160 </aside>161 </div>162 );163}164