This commit is contained in:
lda committed 2026-04-12 03:11:02 +07:00
1 parent d0006f2db5
commit 5efcdf75ea
5 files changed
+323 -10

No files matched your search

+82 -4
View File
@@ -1,3 +1,5 @@
import { useMemo, useState } from "react";
import type { Alert, AlertTransition } from "@/api";
type Props = {
@@ -7,6 +9,44 @@ type Props = {
};
export function AlertsPage({ alerts, transitions, onRefresh }: Props) {
const [severity, setSeverity] = useState("all");
const [status, setStatus] = useState("all");
const [kind, setKind] = useState("all");
const [transitionQ, setTransitionQ] = useState("");
const severities = useMemo(
() => ["all", ...Array.from(new Set(alerts.map((a) => a.severity))).sort()],
[alerts],
);
const statuses = useMemo(
() => ["all", ...Array.from(new Set(alerts.map((a) => a.status))).sort()],
[alerts],
);
const kinds = useMemo(
() => ["all", ...Array.from(new Set(alerts.map((a) => a.kind))).sort()],
[alerts],
);
const filteredAlerts = useMemo(
() => alerts.filter((a) => (
(severity === "all" || a.severity === severity)
&& (status === "all" || a.status === status)
&& (kind === "all" || a.kind === kind)
)),
[alerts, severity, status, kind],
);
const filteredTransitions = useMemo(() => {
const q = transitionQ.trim().toLowerCase();
if (!q) return transitions;
return transitions.filter((t) => (
t.kind.toLowerCase().includes(q)
|| t.to_status.toLowerCase().includes(q)
|| t.message.toLowerCase().includes(q)
|| (t.agent_id || "").toLowerCase().includes(q)
));
}, [transitions, transitionQ]);
return (
<section className="two-col">
<div className="card">
@@ -14,20 +54,58 @@ export function AlertsPage({ alerts, transitions, onRefresh }: Props) {
<h2>Active Alerts</h2>
<button onClick={() => void onRefresh()}>Refresh</button>
</div>
<div className="grid-3 compact">
<label>
Severity
<select value={severity} onChange={(e) => setSeverity(e.target.value)}>
{severities.map((v) => (
<option key={v} value={v}>{v}</option>
))}
</select>
</label>
<label>
Status
<select value={status} onChange={(e) => setStatus(e.target.value)}>
{statuses.map((v) => (
<option key={v} value={v}>{v}</option>
))}
</select>
</label>
<label>
Kind
<select value={kind} onChange={(e) => setKind(e.target.value)}>
{kinds.map((v) => (
<option key={v} value={v}>{v}</option>
))}
</select>
</label>
</div>
<p className="muted">Showing {filteredAlerts.length} of {alerts.length}</p>
<div className="list">
{alerts.map((alert) => (
{filteredAlerts.map((alert) => (
<div className="row plain" key={alert.alert_id}>
<span>{alert.kind}{alert.agent_id ? ` (${alert.agent_id})` : ""}</span>
<span>{alert.severity}</span>
</div>
))}
{!alerts.length && <div className="empty">No active alerts</div>}
{!filteredAlerts.length && <div className="empty">No active alerts</div>}
</div>
</div>
<div className="card">
<h2>Transition History</h2>
<pre className="output small">{JSON.stringify(transitions, null, 2)}</pre>
<div className="row-head">
<h2>Transition History</h2>
<span className="muted">{filteredTransitions.length} shown</span>
</div>
<label>
Search
<input
value={transitionQ}
onChange={(e) => setTransitionQ(e.target.value)}
placeholder="kind, status, message, agent"
/>
</label>
<pre className="output small">{JSON.stringify(filteredTransitions, null, 2)}</pre>
</div>
</section>
);