Initial commit
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user