/** 失败告警浮层:轮询桥接告警,新失败弹出 toast,可一键发起诊断会话。 */ import { useEffect } from 'react' import { useSyncExternalStore } from 'react' import { getState, subscribe, update, dismissToast, pushToast } from './store.js' import { api } from './api.js' function useWorkbench() { return useSyncExternalStore(subscribe, getState) } export function Toasts() { const s = useWorkbench() useEffect(() => { let stopped = false let timer = null const poll = async () => { try { const payload = await api.alerts() const fresh = (payload.alerts ?? []).filter( (alert) => !alert.seen && !getState().seenAlertIds[alert.id], ) if (fresh.length) { const seen = { ...getState().seenAlertIds } for (const alert of fresh) { seen[alert.id] = true pushToast({ kind: 'failed', text: `工作流「${alert.name}」运行失败`, alert }) } update({ seenAlertIds: seen }) } } catch { // 桥接离线时静默 } if (!stopped) timer = setTimeout(poll, 30_000) } timer = setTimeout(poll, 8_000) return () => { stopped = true if (timer) clearTimeout(timer) } }, []) if (!s.toasts.length) return null return (