/** * Active alarms, most severe first. * * Every alarm carries its severity as a WORD as well as a colour, and "Explain" * hands the alarm to the copilot - which is the moment the demo stops looking * like a dashboard and starts looking like a twin that understands itself. */ import { useStore } from '../store.js'; import { duration } from '../lib/format.js'; const SEVERITY_ORDER = ['critical', 'major', 'warning', 'predictive', 'info']; export function AlarmFeed({ onExplain }) { const frame = useStore((s) => s.frame); const select = useStore((s) => s.select); if (!frame) return null; const alarms = frame.analytics.alarms; const counts = SEVERITY_ORDER.map((sev) => ({ sev, n: alarms.filter((a) => a.severity === sev).length, })).filter((x) => x.n > 0); return (

Alarms {counts.length ? counts.map((c) => `${c.n} ${c.sev}`).join(' ยท ') : 'all clear'}

{alarms.length === 0 ? (
No active alarms. All signals are within limits and no threshold crossings are projected.
) : (
{alarms.map((a) => (
{a.severity === 'predictive' ? 'Trend' : a.severity} {duration(frame.t - a.raisedAt)} ago
{a.message}
))}
)}
); }