// — `/alerts`' content: the alerts the swarm's Grafana holds // now, from swarm-controller's `GET /api/alerts`. Only the firing ones show at // first; a button in the header adds the pending, no-data and errored ones. // Same shape as `HivesPage`: one fetch on a `RefreshIntervalPicker` cadence, // rendered as a `Table`. import { useState } from "preact/hooks"; import { ApiErrorPanel } from "@hive/shared/api-error-panel.js"; import { Badge, type BadgeTone } from "@hive/shared/badge.js"; import { Button } from "../ui/button/Button.js"; import { Panel } from "../ui/panel/Panel.js"; import { RelativeTime } from "../ui/relative-time/RelativeTime.js"; import { RefreshIntervalPicker, type RefreshIntervalMs, } from "../ui/refresh-interval/RefreshInterval.js"; import { fetchJson, usePolled } from "../ui/polled/usePolled.js"; import { Table, type TableColumn } from "../ui/table/Table.js"; import { activeSinceMs, alertKey, listedAlerts, type Alert } from "./alerts.js"; const STATE_TONE: Record = { Alerting: "negative", Error: "negative", NoData: "warning", Pending: "warning", }; // Grafana's own alert list, for what this page does not show. const GRAFANA_ALERTS_URL = "https://grafana.constellation.darkest.space/alerting/groups"; const COLUMNS: TableColumn[] = [ { key: "name", header: "alert", render: (a) => a.name, sortBy: (a) => a.name, filterValue: (a) => a.name, }, { key: "state", header: "state", render: (a) => { const since = activeSinceMs(a); return ( {a.state} () ) : ( a.state ) } /> ); }, sortBy: (a) => a.state, filterValues: (a) => [a.state], filterMode: "multiselect", }, { key: "summary", header: "summary", render: (a) => a.summary ?? "—", sortBy: (a) => a.summary ?? "", filterValue: (a) => a.summary ?? "", }, ]; const DEFAULT_INTERVAL_MS: RefreshIntervalMs = 30_000; export function AlertsPage() { const [showAll, setShowAll] = useState(false); const [intervalMs, setIntervalMs] = useState(DEFAULT_INTERVAL_MS); const { data: alerts, error } = usePolled(intervalMs, (signal) => fetchJson("/api/alerts", signal), ); const listed = alerts ? listedAlerts(alerts, showAll) : null; const hidden = alerts && listed ? alerts.length - listed.length : 0; return ( Grafana's alert list {showAll || hidden > 0 ? ( ) : null} } > {error ? ( ) : null} {!error && alerts === null ?

loading…

: null} {listed && listed.length === 0 ? (

{showAll ? "no alerts." : "nothing is alerting."}

) : null} {listed && listed.length > 0 ? ( ) : null} ); }