import { useMemo, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Button, Modal, Input } from "@heroui/react"; import { apiPost, applyUmeTopologyToFabric, disconnectUmeToken, fetchUmeNe, cancelUmeAlarmSubscription, clearLocalUmeAlarmSubscription, establishUmeAlarmSubscription, fetchUmeAlarmSubscriptionStatus, fetchUmeAlarmKeywords, fetchUmeInventoryNeTypes, fetchUmeKeyAlertMonitor, fetchUmeNotificationIds, fetchUmeSyncStatus, fetchUmeTokenStatus, fetchCliTargets, refreshUmeToken, upsertUmeKeyAlertRule, deleteUmeKeyAlertRule, patchUmeKeyAlertRule, updateUmeKeyAlertMonitorConfig, } from "../services/api"; import { HelpHint } from "../components/HelpHint"; import { UmeCliConnectPanel } from "../components/UmeCliConnectPanel"; import { AppModalShell } from "../components/ui/AppModalShell"; import { queryKeys } from "../constants/queryKeys"; import { useI18n } from "../i18n"; import { useToast } from "../hooks/useToast"; import type { UmeAlarmSubscriptionStatus, UmeKeyAlertRuleItem } from "../types"; import { pageCount, runtimeIntervalLabel } from "../utils/display"; import { runtimeLastError, wsConnectionLabel } from "../utils/runtimeMessages"; import { formatSystemTime } from "../utils/time"; import { openOrFocusModule } from "../utils/moduleWindows"; import { jobChipColor, NmStatusChip, type NmChipColor } from "./network/nmChips"; function tokenChipColor(opts: { hasToken: boolean; needsRenewal: boolean; }): NmChipColor { if (!opts.hasToken) return "danger"; if (opts.needsRenewal) return "warning"; return "success"; } function pillLevelToChip(level: string | undefined): NmChipColor { const s = String(level || "").toLowerCase(); if (s === "up" || s === "ok" || s === "pass") return "success"; if (s === "down" || s === "fail" || s === "error") return "danger"; if (s === "warn" || s === "warning" || s === "medium") return "warning"; return "default"; } export function UmePage() { const { t } = useI18n(); const { showOk, showError } = useToast(); const queryClient = useQueryClient(); const [tokenOpError, setTokenOpError] = useState(""); const [runtimeTaskError, setRuntimeTaskError] = useState(""); const [subscriptionOpError, setSubscriptionOpError] = useState(""); const [syncPage, setSyncPage] = useState(1); const [syncPageSize, setSyncPageSize] = useState(10); const [neKeyword, setNeKeyword] = useState(""); const [nePage, setNePage] = useState(1); const [nePageSize, setNePageSize] = useState(10); const [expandedNeId, setExpandedNeId] = useState(""); const [nePanelOpen, setNePanelOpen] = useState(false); const [syncStatusPanelOpen, setSyncStatusPanelOpen] = useState(false); const [keyAlertPanelOpen, setKeyAlertPanelOpen] = useState(false); const [keyAlertMatchType, setKeyAlertMatchType] = useState<"notification_id" | "keyword">("keyword"); const [keyAlertMatchValue, setKeyAlertMatchValue] = useState(""); const [keyAlertLabel, setKeyAlertLabel] = useState(""); const [keyAlertOpError, setKeyAlertOpError] = useState(""); const [keyAlertKeywordHints, setKeyAlertKeywordHints] = useState([]); const [keyAlertIdHints, setKeyAlertIdHints] = useState< Array<{ notification_id: string; native_probable_cause_sample: string }> >([]); const [keyAlertPage, setKeyAlertPage] = useState(1); const [keyAlertPageSize, setKeyAlertPageSize] = useState(10); const [keyAlertFilterKeyword, setKeyAlertFilterKeyword] = useState(""); const [keyAlertFilterEnabled, setKeyAlertFilterEnabled] = useState<"" | "true" | "false">(""); const [keyAlertFilterMatchType, setKeyAlertFilterMatchType] = useState<"" | "notification_id" | "keyword">(""); const [keyAlertNeTypes, setKeyAlertNeTypes] = useState([]); const [keyAlertEditRule, setKeyAlertEditRule] = useState(null); const [keyAlertEditNeTypes, setKeyAlertEditNeTypes] = useState([]); const [cliPanelOpen, setCliPanelOpen] = useState(false); const syncStatusQuery = useQuery({ queryKey: queryKeys.umeSyncStatus(syncPage, syncPageSize), queryFn: () => fetchUmeSyncStatus({ page: syncPage, pageSize: syncPageSize }), staleTime: 10_000, // Panel open or active sync → keep snappy; otherwise idle cards only need a slow heartbeat. refetchInterval: (q) => { const items = q.state.data?.items || []; const running = items.some((x) => String(x.status || "").toLowerCase() === "running"); if (syncStatusPanelOpen || running) return 5000; return 20_000; }, refetchIntervalInBackground: false, }); const tokenStatusQuery = useQuery({ queryKey: queryKeys.umeTokenStatus, queryFn: fetchUmeTokenStatus, staleTime: 15_000, refetchInterval: 20_000, refetchIntervalInBackground: false, }); const tokenRefreshMutation = useMutation({ mutationFn: refreshUmeToken, onMutate: () => setTokenOpError(""), onSuccess: async (res) => { if (!res?.ok) { const msg = String(res.error || res.error_kind || "token_refresh_failed"); setTokenOpError(msg); showError(msg); } else { setTokenOpError(""); showOk(res.changed ? t("ume.token.renewOkChanged") : t("ume.token.renewOkSame")); } await queryClient.invalidateQueries({ queryKey: queryKeys.umeTokenStatus }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => { const msg = String(err); setTokenOpError(msg); showError(msg); }, }); const subscriptionStatusQuery = useQuery({ queryKey: queryKeys.umeAlarmSubscription, queryFn: fetchUmeAlarmSubscriptionStatus, staleTime: 10_000, refetchInterval: 15_000, refetchIntervalInBackground: false, }); const keyAlertMonitorQuery = useQuery({ queryKey: queryKeys.umeKeyAlertMonitor( keyAlertPage, keyAlertPageSize, keyAlertFilterKeyword, keyAlertFilterEnabled, keyAlertFilterMatchType, ), queryFn: () => fetchUmeKeyAlertMonitor({ page: keyAlertPage, pageSize: keyAlertPageSize, keyword: keyAlertFilterKeyword, enabled: keyAlertFilterEnabled, matchType: keyAlertFilterMatchType, }), staleTime: keyAlertPanelOpen ? 3000 : 15_000, refetchInterval: keyAlertPanelOpen ? 5000 : 20_000, refetchIntervalInBackground: false, }); const keyAlertNeTypesQuery = useQuery({ queryKey: queryKeys.umeInventoryNeTypes, queryFn: () => fetchUmeInventoryNeTypes(), staleTime: 60_000, enabled: keyAlertPanelOpen || Boolean(keyAlertEditRule), }); const confirmClearLocalSubscription = (hint?: string) => window.confirm(hint || t("ume.subscription.confirmClearDefault")); const subscriptionEstablishMutation = useMutation({ mutationFn: (opts?: { forceReestablish?: boolean }) => establishUmeAlarmSubscription(opts), onMutate: () => setSubscriptionOpError(""), onSuccess: async (res) => { if (!res?.active) { const msg = t("ume.subscription.establishInvalid"); setSubscriptionOpError(msg); showError(msg); } else { setSubscriptionOpError(""); showOk(res.already_exists ? t("ume.subscription.establishExists") : t("ume.subscription.establishOk")); } await queryClient.invalidateQueries({ queryKey: queryKeys.umeAlarmSubscription }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => { const msg = String(err); setSubscriptionOpError(msg); showError(msg); }, }); const subscriptionClearLocalMutation = useMutation({ mutationFn: clearLocalUmeAlarmSubscription, onMutate: () => setSubscriptionOpError(""), onSuccess: async () => { setSubscriptionOpError(""); showOk(t("ume.subscription.clearLocalOk")); await queryClient.invalidateQueries({ queryKey: queryKeys.umeAlarmSubscription }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => { const msg = String(err); setSubscriptionOpError(msg); showError(msg); }, }); const subscriptionCancelMutation = useMutation({ mutationFn: (opts?: { forceClearLocal?: boolean }) => cancelUmeAlarmSubscription(opts), onMutate: () => setSubscriptionOpError(""), onSuccess: async (res) => { if (res?.needs_local_cleanup) { const msg = res.message || t("ume.subscription.serverLostMsg"); if (confirmClearLocalSubscription(msg)) { subscriptionCancelMutation.mutate({ forceClearLocal: true }); return; } setSubscriptionOpError(msg); showError(msg); await queryClient.invalidateQueries({ queryKey: queryKeys.umeAlarmSubscription }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); return; } if (res?.active) { const msg = t("ume.subscription.cancelFailed"); setSubscriptionOpError(msg); showError(msg); } else { setSubscriptionOpError(""); showOk(res?.ume_already_missing ? t("ume.subscription.cancelOkMissing") : t("ume.subscription.cancelOk")); } await queryClient.invalidateQueries({ queryKey: queryKeys.umeAlarmSubscription }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => { const msg = String(err); setSubscriptionOpError(msg); showError(msg); }, }); const tokenDisconnectMutation = useMutation({ mutationFn: disconnectUmeToken, onMutate: () => setTokenOpError(""), onSuccess: async (res) => { if (!res?.ok) { const msg = String(res.error || res.error_kind || "token_disconnect_failed"); setTokenOpError(msg); showError(msg); } else { setTokenOpError(""); showOk(t("ume.token.disconnectOk")); } await queryClient.invalidateQueries({ queryKey: queryKeys.umeTokenStatus }); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => { const msg = String(err); setTokenOpError(msg); showError(msg); }, }); const tokenExpiresIn = Number(tokenStatusQuery.data?.expires_in_s || 0); const hasToken = Boolean(tokenStatusQuery.data?.has_token); const tokenNeedsRenewal = hasToken && tokenExpiresIn <= 0; const tokenLevel = !hasToken ? "down" : tokenNeedsRenewal ? "warn" : tokenExpiresIn < 15 ? "down" : tokenExpiresIn < 60 ? "unknown" : "up"; const neQuery = useQuery({ queryKey: queryKeys.umeNE(neKeyword, nePage, nePageSize), queryFn: () => fetchUmeNe({ keyword: neKeyword, page: nePage, pageSize: nePageSize }), staleTime: 5000, }); const cliTargetsQuery = useQuery({ queryKey: queryKeys.cliTargets(neKeyword, nePage, nePageSize), queryFn: () => fetchCliTargets({ source: "ume", keyword: neKeyword, page: nePage, pageSize: nePageSize }), enabled: nePanelOpen, staleTime: 5000, }); const cliStatusByNeId = useMemo(() => { const map = new Map(); for (const row of cliTargetsQuery.data?.items || []) { map.set(row.id, row.connect_status); } return map; }, [cliTargetsQuery.data]); const runningTasks = (syncStatusQuery.data?.items || []).filter((x) => String(x.status || "").toLowerCase() === "running"); const runtimeTasks = syncStatusQuery.data?.runtime_tasks || []; const topologyFabric = syncStatusQuery.data?.topology_fabric; const needsFabricApply = Boolean(topologyFabric?.needs_apply); const applyFabricMut = useMutation({ mutationFn: () => applyUmeTopologyToFabric(), onSuccess: async () => { showOk(t("ume.syncStatus.applyFabricOk")); await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); await queryClient.invalidateQueries({ queryKey: queryKeys.topologyTree }); }, onError: (err) => showError(String(err)), }); const alarmSub: UmeAlarmSubscriptionStatus = subscriptionStatusQuery.data ?? syncStatusQuery.data?.alarm_subscription ?? { active: false }; const wsConsumer = runtimeTasks.find((x) => x.task === "alarms_current_ws_consumer"); const wsConn = subscriptionStatusQuery.data?.ws_connection; const wsState = String(wsConn?.state || ""); const wsPaused = Boolean(wsConsumer?.paused); const wsLabel = (wsPaused ? t("ume.subscription.wssPaused") : wsConnectionLabel(wsState, wsConn?.label, t)) || runtimeLastError(wsConsumer?.last_error, t) || wsConsumer?.status || t("common.empty"); const subscriptionActive = Boolean(alarmSub.active); const serverSubLost = Boolean( subscriptionStatusQuery.data?.server_subscription_lost ?? alarmSub.server_subscription_lost, ); const serverSubLostReason = String( subscriptionStatusQuery.data?.server_subscription_lost_reason ?? alarmSub.server_subscription_lost_reason ?? "", ); const currentAlarmsMode = subscriptionStatusQuery.data?.current_alarms_mode ?? alarmSub.current_alarms_mode ?? "rest"; const scheduledSyncSkipped = Boolean( subscriptionStatusQuery.data?.scheduled_sync_skipped ?? alarmSub.scheduled_sync_skipped, ); const wsPillLevel = serverSubLost || wsState === "subscription_lost" ? "warn" : wsPaused || wsState === "paused" ? "warn" : wsState === "connected" ? "up" : wsState === "connecting" || wsState === "reconnecting" || wsState === "waiting_token" ? "warn" : wsState === "no_subscription" || wsState === "disconnected" || wsState === "error" || wsState === "init" ? "down" : String(wsConsumer?.last_error || "").includes("connected") || String(wsConsumer?.last_error || "").includes("ws:connected") ? "up" : "unknown"; const wsLogs = [...(subscriptionStatusQuery.data?.ws_logs ?? alarmSub.ws_logs ?? [])].reverse(); const subPending = subscriptionEstablishMutation.isPending || subscriptionCancelMutation.isPending || subscriptionClearLocalMutation.isPending; const runtimeTaskMutation = useMutation({ mutationFn: async (vars: { task: string; action: "pause" | "resume" }) => apiPost<{ ok: boolean }>(`/v1/ume/runtime/tasks/${encodeURIComponent(vars.task)}/${vars.action}`, {}), onMutate: () => setRuntimeTaskError(""), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: queryKeys.umeSyncStatusAll }); }, onError: (err) => setRuntimeTaskError(String(err)), }); const keyAlertAddMutation = useMutation({ mutationFn: () => upsertUmeKeyAlertRule({ match_type: keyAlertMatchType, match_value: keyAlertMatchValue.trim(), label: keyAlertLabel.trim(), enabled: true, ne_types: keyAlertNeTypes, }), onMutate: () => setKeyAlertOpError(""), onSuccess: async () => { setKeyAlertMatchValue(""); setKeyAlertLabel(""); setKeyAlertNeTypes([]); showOk(t("ume.keyAlert.addOk")); await queryClient.invalidateQueries({ queryKey: queryKeys.umeKeyAlertMonitorAll }); await queryClient.invalidateQueries({ queryKey: ["opsTasks"] }); }, onError: (err) => { const msg = String(err); setKeyAlertOpError(msg); showError(msg); }, }); const keyAlertDeleteMutation = useMutation({ mutationFn: (notificationId: string) => deleteUmeKeyAlertRule(notificationId), onMutate: () => setKeyAlertOpError(""), onSuccess: async () => { showOk(t("ume.keyAlert.deleteOk")); await queryClient.invalidateQueries({ queryKey: queryKeys.umeKeyAlertMonitorAll }); await queryClient.invalidateQueries({ queryKey: ["opsTasks"] }); }, onError: (err) => { const msg = String(err); setKeyAlertOpError(msg); showError(msg); }, }); const keyAlertToggleMutation = useMutation({ mutationFn: (vars: { ruleKey: string; enabled: boolean }) => patchUmeKeyAlertRule(vars.ruleKey, { enabled: vars.enabled }), onMutate: () => setKeyAlertOpError(""), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: queryKeys.umeKeyAlertMonitorAll }); }, onError: (err) => { const msg = String(err); setKeyAlertOpError(msg); showError(msg); }, }); const keyAlertEditMutation = useMutation({ mutationFn: (vars: { ruleKey: string; ne_types: string[] }) => patchUmeKeyAlertRule(vars.ruleKey, { ne_types: vars.ne_types }), onMutate: () => setKeyAlertOpError(""), onSuccess: async () => { setKeyAlertEditRule(null); showOk(t("ume.keyAlert.editOk")); await queryClient.invalidateQueries({ queryKey: queryKeys.umeKeyAlertMonitorAll }); }, onError: (err) => { const msg = String(err); setKeyAlertOpError(msg); showError(msg); }, }); const keyAlertConfigMutation = useMutation({ mutationFn: (forwardOnClear: boolean) => updateUmeKeyAlertMonitorConfig({ forward_on_clear: forwardOnClear }), onMutate: () => setKeyAlertOpError(""), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: queryKeys.umeKeyAlertMonitorAll }); }, onError: (err) => { const msg = String(err); setKeyAlertOpError(msg); showError(msg); }, }); const syncTotal = Number(syncStatusQuery.data?.total || 0); const syncPages = pageCount(syncTotal, syncPageSize); const neTotal = Number(neQuery.data?.total || 0); const nePages = pageCount(neTotal, nePageSize); const expandedNe = useMemo( () => (neQuery.data?.items || []).find((x) => x.ne_id === expandedNeId) || null, [neQuery.data, expandedNeId], ); const keyAlertHub = keyAlertMonitorQuery.data?.dsh_alarm_hub; const keyAlertHubConnections = keyAlertHub?.connections || []; const keyAlertHubSubscribers = Number(keyAlertHub?.subscribers || keyAlertHubConnections.length || 0); const keyAlertRules = keyAlertMonitorQuery.data?.rules || []; const keyAlertTotal = Number(keyAlertMonitorQuery.data?.total || keyAlertRules.length); const keyAlertPages = pageCount(keyAlertTotal, keyAlertPageSize); const keyAlertForwardOnClear = Boolean(keyAlertMonitorQuery.data?.config?.forward_on_clear); const hubWsPill = keyAlertHubSubscribers > 0 ? "up" : "down"; const runtimeTaskLabel = (task: string) => { const key = `ume.tasks.runtimeTask.${task}`; const label = t(key); return label === key ? task : label; }; const perPage = (n: number) => t("common.perPage", { n: String(n) }); return ( <>

{t("ume.token.title")}

token:{" "} {!hasToken ? t("ume.token.disconnected") : tokenNeedsRenewal ? t("ume.token.connectedRenew") : t("ume.token.connected")} {t("ume.token.expiresIn")}:{" "} {typeof tokenStatusQuery.data?.expires_in_s === "number" ? tokenNeedsRenewal ? t("ume.token.needsRenew") : `${tokenStatusQuery.data.expires_in_s}s` : t("common.empty")} {tokenStatusQuery.data?.token_preview ? ( {t("ume.token.preview")}: {tokenStatusQuery.data.token_preview} ) : null}
{(tokenOpError || tokenRefreshMutation.error || tokenDisconnectMutation.error) && (
{t("common.opFailed")}: {tokenOpError || String(tokenRefreshMutation.error || tokenDisconnectMutation.error)}
)}

{t("ume.subscription.title")}

{t("ume.subscription.sub")}:{" "} {subscriptionActive ? t("ume.subscription.subActive") : t("ume.subscription.subInactive")} {subscriptionActive && alarmSub.subscription_id ? ( id: {String(alarmSub.subscription_id).slice(0, 12)}… ) : null} {subscriptionActive || wsConsumer ? ( WSS: {wsLabel} ) : null}
{scheduledSyncSkipped && !serverSubLost ? (
{t("ume.subscription.wssModeBanner", { mode: currentAlarmsMode })}
) : null} {serverSubLost ? (
{t("ume.subscription.serverLostBanner")} {serverSubLostReason ? (
{serverSubLostReason.slice(0, 280)}
) : null}
) : null}
{serverSubLost && subscriptionActive ? ( ) : null}
{subscriptionOpError ? (
{t("ume.subscription.opFailed")}: {subscriptionOpError}
) : null}
{t("ume.subscription.wsLogs")} {wsConsumer?.last_run_at ? t("ume.subscription.wsActivity", { time: formatSystemTime(String(wsConsumer.last_run_at)) }) : t("ume.subscription.wsAutoRefresh")}
{wsLogs.length === 0 ? (
{t("ume.subscription.wsLogsEmpty")}
) : ( wsLogs.map((line, idx) => { const lvl = String(line.level || "info").toLowerCase(); const cls = lvl === "error" ? "ws-log-line--error" : lvl === "warning" ? "ws-log-line--warning" : "ws-log-line--info"; return (
{formatSystemTime(line.ts)} [{lvl}] {line.message} {line.subscription_id ? ( · {String(line.subscription_id).slice(0, 8)}… ) : null}
); }) )}

{t("ume.tasks.currentTitle")}

0 ? "accent" : "success"}> {t("ume.tasks.running")}: {runningTasks.length}
{needsFabricApply ? (
{t("ume.syncStatus.fabricGapTitle")}
{t("ume.syncStatus.fabricGapHint") .replace("{{dock}}", String(topologyFabric?.dock_me_count ?? 0)) .replace("{{fabric}}", String(topologyFabric?.fabric_ume_count ?? 0)) .replace( "{{status}}", String(topologyFabric?.latest_topology_status || topologyFabric?.latest_topology_error || "—"), )}
) : null}
{runningTasks.map((x) => ( ))} {!syncStatusQuery.isLoading && runningTasks.length === 0 && ( )}
ID domain trigger_mode status started_at error
{x.id} {x.domain} {x.trigger_mode} {x.status} {formatSystemTime(x.started_at)} {x.error_message || t("common.empty")}
{t("ume.tasks.noRunning")}

{t("ume.tasks.runtimeTitle")}

{runtimeTaskError ? (
{t("ume.tasks.runtimeOpFailed")}: {runtimeTaskError}
) : null}
{runtimeTasks.map((x) => ( ))} {!syncStatusQuery.isLoading && runtimeTasks.length === 0 && ( )}
task interval status last_run_at {t("ume.tasks.lastErrorCol")} actions
{runtimeTaskLabel(x.task)} {runtimeIntervalLabel(x.interval_label)} {x.status} {x.last_run_at ? formatSystemTime(x.last_run_at) : t("common.empty")} {runtimeLastError(x.last_error, t) || t("common.empty")} {Boolean(x.paused) ? ( ) : ( )}
{t("ume.tasks.noRuntime")}

{t("ume.cli.title")}

{t("ume.cli.hint")}

{t("ume.keyAlert.title")}

{t("ume.keyAlert.hub")}:{" "} {keyAlertHubSubscribers > 0 ? t("ume.keyAlert.hubConnected") : t("ume.keyAlert.hubEmpty")} {t("ume.keyAlert.hubSubscribers")}: {keyAlertHubSubscribers} {t("ume.keyAlert.hubPublished")}: {Number(keyAlertHub?.published || 0)} {t("ume.keyAlert.hubDeliverOk")}: {Number(keyAlertHub?.deliver_ok || 0)}

{t("ume.syncStatus.title")}

{syncTotal ? t("ume.syncStatus.summary", { total: String(syncTotal), running: String(runningTasks.length), }) : t("ume.syncStatus.empty")}

{t("ume.ne.title")}

{t("ume.ne.summary", { total: String(neTotal) })}

setCliPanelOpen(false)} size="lg" className="app-heroui-modal--xl" > {t("ume.cli.title")}

{t("ume.cli.hint")}

setKeyAlertPanelOpen(false)} size="lg" className="app-heroui-modal--xl" > {t("ume.keyAlert.title")}

{t("ume.keyAlert.hub")}:{" "} {keyAlertHubSubscribers > 0 ? t("ume.keyAlert.hubConnected") : t("ume.keyAlert.hubEmpty")} {` · ${t("ume.keyAlert.hubSubscribers")} ${keyAlertHubSubscribers}`} {` · ${t("ume.keyAlert.hubPublished")} ${Number(keyAlertHub?.published || 0)}`} {` · ${t("ume.keyAlert.hubDeliverOk")} ${Number(keyAlertHub?.deliver_ok || 0)}`} {keyAlertHub?.path ? ` · ${t("ume.keyAlert.hubPath")} ${keyAlertHub.path}` : ""}

{t("ume.keyAlert.hubConnections")}
{keyAlertHubConnections.length === 0 ? (

{t("ume.keyAlert.hubEmptyConnections")}

) : (
{keyAlertHubConnections.map((conn) => ( ))}
{t("ume.keyAlert.hubColId")} {t("ume.keyAlert.hubColUser")} {t("ume.keyAlert.hubColRemote")} {t("ume.keyAlert.hubColClient")} {t("ume.keyAlert.hubColConnected")} {t("ume.keyAlert.hubColLastSeen")}
{conn.id} {conn.user || "-"} {conn.remote || "-"} {conn.client || "-"} {conn.connected_at ? formatSystemTime(conn.connected_at) : "-"} {conn.last_seen_at ? formatSystemTime(conn.last_seen_at) : "-"}
)}
setKeyAlertMatchValue(e.target.value)} list="ume-key-alert-match-options" /> setKeyAlertLabel(e.target.value)} /> {keyAlertMatchType === "keyword" ? keyAlertKeywordHints.map((kw) => ))}
{t("ume.keyAlert.neTypesLabel")}
{keyAlertNeTypesQuery.isLoading ? ( {t("common.refreshing")} ) : (keyAlertNeTypesQuery.data?.items || []).length === 0 ? ( {t("ume.keyAlert.neTypesEmpty")} ) : (
{(keyAlertNeTypesQuery.data?.items || []).map((item) => ( ))}
)}

{t("ume.keyAlert.neTypesHint")}

{keyAlertOpError ? (

{t("common.opFailed")}: {keyAlertOpError}

) : null}
{ setKeyAlertFilterKeyword(e.target.value); setKeyAlertPage(1); }} />
{keyAlertRules.map((rule) => ( ))} {!keyAlertMonitorQuery.isLoading && keyAlertRules.length === 0 ? ( ) : null}
{t("ume.keyAlert.colMonitor")} {t("ume.keyAlert.colType")} {t("ume.keyAlert.colMatch")} {t("ume.keyAlert.colLabel")} {t("ume.keyAlert.colNeTypes")} {t("ume.keyAlert.colPublished")} {t("ume.keyAlert.colAttempts")} {t("ume.keyAlert.colLast")} {t("ume.keyAlert.colActions")}
{rule.match_type === "keyword" ? t("ume.keyAlert.matchKeyword") : t("ume.keyAlert.matchNotificationId")} {rule.match_value || rule.notification_id} {rule.label || t("common.empty")} {rule.ne_types?.length ? rule.ne_types.join(", ") : t("ume.keyAlert.neTypesAll")} {Number(rule.forward_stats?.published_ok || 0)} {Number(rule.forward_stats?.attempts || 0)} {rule.forward_stats?.last_forwarded_at ? formatSystemTime(rule.forward_stats.last_forwarded_at) : t("common.empty")}
{t("ume.keyAlert.emptyRules")}
{t("common.pagerMeta", { total: String(keyAlertTotal), page: String(keyAlertPage), pages: String(keyAlertPages), })}
setSyncStatusPanelOpen(false)} size="lg" className="app-heroui-modal--xl" > {t("ume.syncStatus.title")}

{t("ume.syncStatus.summary", { total: String(syncTotal), running: String(runningTasks.length), })}

{(syncStatusQuery.data?.items || []).map((x) => ( ))} {!syncStatusQuery.isLoading && (syncStatusQuery.data?.items || []).length === 0 ? ( ) : null}
ID domain status pulled inserted updated deleted started_at ended_at error
{String(x.id).slice(0, 8)} {x.domain} {x.status} {x.pulled_count} {x.inserted_count} {x.updated_count} {Number(x.deleted ?? 0)} {formatSystemTime(x.started_at)} {x.ended_at ? formatSystemTime(x.ended_at) : t("common.empty")} {x.error_message || t("common.empty")}
{t("ume.syncStatus.empty")}
{t("common.pagerMeta", { total: String(syncTotal), page: String(syncPage), pages: String(syncPages), })}
{ setNePanelOpen(false); setExpandedNeId(""); }} size="lg" className="app-heroui-modal--xl" > {t("ume.ne.title")}

{t("ume.ne.summary", { total: String(neTotal) })}

{ setNeKeyword(e.target.value); setNePage(1); }} />
{(neQuery.data?.items || []).map((x) => ( ))} {!neQuery.isLoading && !(neQuery.data?.items || []).length ? ( ) : null}
ne_id user_label ip type device_level host_name {t("ume.ne.cliConnect")} hw_ver last_seen
{x.ne_id} {x.user_label} {x.ip_address} {x.ne_type} {x.device_level || t("common.empty")} {x.host_name || t("common.empty")} {cliStatusByNeId.get(x.ne_id) || "unknown"} {x.hardware_version || t("common.empty")} {x.last_seen_at ? formatSystemTime(x.last_seen_at) : t("common.empty")}
{t("common.empty")}
{t("common.pagerMeta", { total: String(neTotal), page: String(nePage), pages: String(nePages), })}
setExpandedNeId("")} size="lg" > {expandedNe?.user_label || expandedNe?.ne_id || t("ume.ne.expand")} {expandedNe ? ( <>

{expandedNe.ne_id} {expandedNe.ip_address ? ` · ${expandedNe.ip_address}` : ""} {expandedNe.ne_type ? ` · ${expandedNe.ne_type}` : ""}

consistent_state
{expandedNe.consistent_state || t("common.empty")}
admin_status
{expandedNe.admin_status || t("common.empty")}
connection_status
{expandedNe.connection_status || t("common.empty")}
maintain_status
{expandedNe.maintain_status || t("common.empty")}
address_type
{expandedNe.address_type || t("common.empty")}
location
{expandedNe.location || t("common.empty")}
loopback
{expandedNe.loopback || t("common.empty")}
net_mask
{expandedNe.net_mask || t("common.empty")}
mac
{expandedNe.mac || t("common.empty")}
interface_version
{expandedNe.interface_version || t("common.empty")}
create_time
{expandedNe.create_time || t("common.empty")}
creator
{expandedNe.creator || t("common.empty")}
host_name
{expandedNe.host_name || t("common.empty")}
hardware_version
{expandedNe.hardware_version || t("common.empty")}
{t("ume.ne.cliConnect")}
{cliStatusByNeId.get(expandedNe.ne_id) || "unknown"}
last_seen
{expandedNe.last_seen_at ? formatSystemTime(expandedNe.last_seen_at) : t("common.empty")}
) : null}
{ if (!keyAlertEditMutation.isPending) setKeyAlertEditRule(null); }} dismissible={!keyAlertEditMutation.isPending} size="lg" > {t("ume.keyAlert.editTitle")} {keyAlertEditRule ? ( <>

{keyAlertEditRule.match_type === "keyword" ? t("ume.keyAlert.matchKeyword") : t("ume.keyAlert.matchNotificationId")} : {keyAlertEditRule.match_value || keyAlertEditRule.notification_id} {keyAlertEditRule.label ? ` · ${keyAlertEditRule.label}` : ""}

{t("ume.keyAlert.neTypesLabel")}
{keyAlertNeTypesQuery.isLoading ? ( {t("common.refreshing")} ) : (keyAlertNeTypesQuery.data?.items || []).length === 0 ? ( {t("ume.keyAlert.neTypesEmpty")} ) : (
{(keyAlertNeTypesQuery.data?.items || []).map((item) => ( ))}
)}

{t("ume.keyAlert.neTypesHint")}

) : null}
); }