feat(workbench): expand SCADA monitoring and investigation presentation
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { dismissMapNotice, showMapNotice } from "@/features/map/core";
|
||||
import type { WorkbenchAlert } from "../types";
|
||||
|
||||
import { useScadaEventAtmosphere, type ScadaEventTask } from "./use-scada-event-atmosphere";
|
||||
export type { ScadaAlertAtmosphereState } from "./use-scada-event-atmosphere";
|
||||
|
||||
/** Announce newly persisted alerts, including while the peripheral panel is closed. */
|
||||
export function useScadaAlertNotices(
|
||||
projectId: string | null,
|
||||
alerts: WorkbenchAlert[] | null,
|
||||
onOpen: (alert: WorkbenchAlert) => void,
|
||||
tasks: readonly ScadaEventTask[] | null = null
|
||||
) {
|
||||
const atmosphere = useScadaEventAtmosphere(projectId, alerts, tasks);
|
||||
const openRef = useRef(onOpen);
|
||||
openRef.current = onOpen;
|
||||
const state = useRef<{ initialized: boolean; seen: Set<string>; visible: Set<string>; linked: Set<string> }>({
|
||||
initialized: false, seen: new Set(), visible: new Set(), linked: new Set()
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const current = { initialized: false, seen: new Set<string>(), visible: new Set<string>(), linked: new Set<string>() };
|
||||
state.current = current;
|
||||
return () => { current.visible.forEach((id) => dismissMapNotice(id)); };
|
||||
}, [projectId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!alerts) return;
|
||||
const current = state.current;
|
||||
const incoming = alerts.filter((alert) => alert.source && "kind" in alert.source
|
||||
&& alert.source.kind === "scada_replay");
|
||||
const noticeId = (id: string) => `scada-alert:${projectId}:${id}`;
|
||||
const activeIds = new Set(incoming.map((alert) => noticeId(alert.id)));
|
||||
for (const id of current.visible) {
|
||||
if (!activeIds.has(id) && !current.linked.has(id)) {
|
||||
dismissMapNotice(id);
|
||||
current.visible.delete(id);
|
||||
}
|
||||
}
|
||||
for (const alert of incoming) {
|
||||
if (current.seen.has(alert.id)) continue;
|
||||
current.seen.add(alert.id);
|
||||
// Opening a project restores its notification center without replaying old popups.
|
||||
if (!current.initialized) continue;
|
||||
const id = noticeId(alert.id);
|
||||
current.visible.add(id);
|
||||
if (alert.conditionId) current.linked.add(id);
|
||||
showMapNotice({
|
||||
id,
|
||||
title: alert.title,
|
||||
message: alert.description,
|
||||
tone: alert.severity === "critical" ? "error" : "warning",
|
||||
position: "top-center",
|
||||
duration: alert.conditionId ? Infinity : 10_000,
|
||||
actionLabel: alert.conditionId ? "查看调查" : undefined,
|
||||
onAction: alert.conditionId ? () => openRef.current(alert) : undefined
|
||||
});
|
||||
}
|
||||
current.initialized = true;
|
||||
}, [alerts, projectId]);
|
||||
|
||||
return atmosphere;
|
||||
}
|
||||
Reference in New Issue
Block a user