Initial commit

This commit is contained in:
2026-08-24 15:35:32 +05:30
commit fcade251a6
51 changed files with 11565 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
/**
* 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 (
<div className="card">
<h2 className="card-title">
Alarms
<span className="hint">
{counts.length
? counts.map((c) => `${c.n} ${c.sev}`).join(' · ')
: 'all clear'}
</span>
</h2>
{alarms.length === 0 ? (
<div className="empty">
No active alarms. All signals are within limits and no threshold crossings are projected.
</div>
) : (
<div className="alarm-list">
{alarms.map((a) => (
<div className={`alarm ${a.severity}`} key={a.key}>
<div className="alarm-top">
<span className={`sev ${a.severity}`}>
{a.severity === 'predictive' ? 'Trend' : a.severity}
</span>
<button
className="who"
style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer' }}
onClick={() => select(a.station)}
title={`Select ${a.station}`}
>
{a.station}{a.signal ? `.${a.signal}` : ''}
</button>
<span className="muted small" style={{ marginLeft: 'auto' }}>
{duration(frame.t - a.raisedAt)} ago
</span>
</div>
<div className="msg">{a.message}</div>
<div className="actions">
<button onClick={() => onExplain(a)}>Explain this</button>
</div>
</div>
))}
</div>
)}
</div>
);
}