+
+
+
+
+ | Port |
+ Hits / 24h |
+
+
+
+ {(ds.topports ?? []).slice(0, PORT_ROW_LIMIT).map((p) => (
+
+ | {p.port} |
+ {p.records.toLocaleString()} |
+
+ ))}
+
+
+
+
+
+
+ | Source IP |
+ CC |
+ Hits |
+
+
+
+ {(ds.topips ?? []).slice(0, SOURCE_ROW_LIMIT).map((s) => (
+
+ | {s.ip} |
+ {s.country ?? '—'} |
+ {s.records.toLocaleString()} |
+
+ ))}
+
+
+
+
+ {summary && (
+
+ {fmtN(summary.records)} records · {fmtN(summary.sources)} sources ·{' '}
+ {fmtN(summary.targets)} targets — last 24h
+
+ )}
+
+ )
+}
+
+DShieldPanel.displayName = 'DShieldPanel'
+
+function fmtN(n: number): string {
+ if (n >= MILLION) return `${(n / MILLION).toFixed(1)}M`
+ if (n >= THOUSAND) return `${(n / THOUSAND).toFixed(1)}k`
+ return String(n)
+}