// AI-MONITOR · Page sections — Nodes, Models, Telemetry const { NODES: _NODES, MODELS: _MODELS, live: _live, totals: _totals } = window.AIData; // ── NODES ────────────────────────────────────────────────────────────── function NodesSection() { useLive(); const { t } = useLang(); const [active, setActive] = useState(null); const [nfilter, setNfilter] = useState("All"); return (
03{t("Nodes")}

{t("{n} machines. ", { n: _NODES.length })}{t("Each a citizen.")}

{t("Each host runs the LiteLLM gateway, an inference engine, or both. Click a node for the full forensic view.")}

{["All","RTX","DGX","Active"].map((k) => ( ))}
{/* 列数随 hearth.yaml nodes 数量动态: 1-6 节点对应 .g-1 ~ .g-6; 7+ 节点用 .g-auto (auto-fill minmax 220px) 自动换行。 响应式塌缩交给 CSS 媒体查询(≤1180→3 列, ≤820→2 列, 手机→1 列)。 */}
{_NODES.filter((n) => nfilter === "All" ? true : nfilter === "RTX" ? (n.kind || "discrete") === "discrete" : nfilter === "DGX" ? (n.kind || "discrete") !== "discrete" : (_live.nodes[n.id] && _live.nodes[n.id].cpu.now > 0)) .map((n) => setActive(n)} />)}
{active && setActive(null)} />}
); } function NodeCard({ node, onClick }) { const { t } = useLang(); const ns = _live.nodes[node.id]; const isHost = /gateway/i.test(node.role || ""); const offline = ns.up === false; // 后端权威: 真实离线状态(不再写死 ONLINE) return (
{node.class}
{node.name}
{node.ip}
{offline ? t("OFFLINE") : t("ONLINE")}
{isHost ? "GATEWAY" : node.role.split(" ")[2] || "NODE"}
{node.gpuPending ?
GPU
{t("maint. pending")}
: }
GPU
VRAM
CPU
{!node.gpuPending && 80 ? "var(--hot)" : "var(--accent)"} />}
GPU
{node.gpu.name.replace("GeForce ","")}
VRAM
{node.gpu.mem} GB
CPU
{node.cpu.cores}c / {node.cpu.threads}t
RAM
{node.ram} GB
{t("Net")}
{node.net}
{t("Power")}
{node.gpuPending ? t("GPU pending · maintenance window") : ns.power.now.toFixed(0) + " W"}
{t("GPU temp")}
80 ? "var(--hot)" : "var(--ink)" }}>{node.gpuPending ? "—" : ns.tempGpu.now.toFixed(0) + " °C"}
); } function NodeDetail({ node, onClose }) { const { t } = useLang(); const ns = _live.nodes[node.id]; const nicTemp = (_live.nodeMeta?.[node.id]?.temps || []).find((x) => x.module === "网卡" || x.module === "NIC")?.celsius || 0; const hostedModels = _MODELS.filter((m) => m.nodes.includes(node.id)); return (
$ ssh root@{node.ip} {node.name} · {t("forensic view")}
{node.gpu.name} · {node.os} · kernel {node.kernel} · NVIDIA {node.driver.split(" ")[1]} · CUDA {node.cuda}
{t("Accelerator activity · 60 ticks")}
{t("Accelerator activity")}
80 ? "hot" : "ok"} /> {nicTemp > 0 && ( 85 ? "hot" : nicTemp > 70 ? "warn" : "ok"} /> )}
{t("Hosted models")}
{hostedModels.length === 0 &&
{t("— No models pinned to this node —")}
} {hostedModels.map((m) => (
{m.display}
{m.framework} · {m.quant} · :{m.port}
{t(m.state)}
))}
{t("Running services")}
{node.services.map((s) => {s})}
{t("System")}
CPU{node.cpu.model} OS{node.os} {t("Kernel")}{node.kernel} {t("Driver")}{node.driver} CUDA{node.cuda} {t("Net")}{node.net}
{t("Quick actions")}
{["Open SSH session","Drain & cordon","Restart daemons","Pin model…","Run nvidia-smi dmon","Reboot"].map((a) => ( ))}
{t("Hardware sensors")}
); } // 按硬件模块分组的可展开传感器面板(温度各组 + 风扇组)。 // 后端 live.{temps,fans} 已全量直采;此处只负责"应看尽看"的分组呈现。 function SensorPanel({ nodeId }) { const { t } = useLang(); const meta = _live.nodeMeta[nodeId] || {}; const temps = meta.temps || []; const fans = meta.fans || []; const [open, setOpen] = useState({}); if (!temps.length && !fans.length) return
{t("— no temperature data (node unmanaged) —")}
; const tc = (c) => (c >= 80 ? "var(--hot)" : c >= 70 ? "var(--warn)" : "var(--ink)"); const moreRow = (n) => ({ label: t("+{n} more").replace("{n}", n), value: "", color: "var(--ink-3)" }); const order = ["CPU", "水冷", "网卡", "NVMe", "SoC", "平台", "其他"]; const rank = (m) => { const i = order.indexOf(m); return i < 0 ? 99 : i; }; const groups = {}; temps.forEach((x) => { (groups[x.module] = groups[x.module] || []).push(x); }); const cards = Object.keys(groups).sort((a, b) => rank(a) - rank(b)).map((mod) => { const list = groups[mod]; // already hottest-first (global desc sort) const expanded = !!open[mod]; const rows = (expanded ? list : list.slice(0, 3)).map((x) => ({ label: x.label, value: `${Math.round(x.celsius)} °C`, color: tc(x.celsius), })); if (!expanded && list.length > 3) rows.push(moreRow(list.length - 3)); return 3} expanded={expanded} onToggle={() => setOpen((o) => ({ ...o, [mod]: !o[mod] }))} />; }); if (fans.length) { const expanded = !!open.__fans; const repRpm = Math.max(...fans.map((f) => f.rpm)); const rows = (expanded ? fans : fans.slice(0, 3)).map((f) => ({ label: f.label, value: f.rpm > 0 ? `${f.rpm} RPM` : t("stopped"), color: f.rpm > 0 ? "var(--ink)" : "var(--ink-3)", })); if (!expanded && fans.length > 3) rows.push(moreRow(fans.length - 3)); cards.push( 3} expanded={expanded} onToggle={() => setOpen((o) => ({ ...o, __fans: !o.__fans }))} />); } return
{cards}
; } function SensorGroup({ title, rep, repColor, rows, expandable, expanded, onToggle }) { return (
{rows.map((r, i) => (
{r.label} {r.value}
))}
); } function DetailMetric({ label, value, unit, bar, color = "accent" }) { return (
{label}
{value}{unit}
); } // ── MODELS ───────────────────────────────────────────────────────────── function ModelsSection() { useLive(); const { t } = useLang(); const [active, setActive] = useState(null); const [filter, setFilter] = useState("all"); const visible = _MODELS.filter((m) => { if (filter === "all") return true; if (filter === "serving") return m.state === "serving"; if (filter === "idle") return m.state !== "serving"; if (filter === "chat") return m.kind === "chat"; return true; }); return (
04{t("Models · LiteLLM gateway")}

{t("One endpoint. ")}{t("Every model.")}

{t("All inference is routed through LiteLLM on ")}{(_live.cluster && _live.cluster.gatewayHost) || "127.0.0.1:4000"}{t(" — OpenAI-compatible API, smart routing, fallbacks, cost & token accounting. Cold models spin up on demand to fit the VRAM budget.")}

{[["all","All"],["serving","Serving"],["idle","Idle"],["chat","Chat"]].map(([k, l]) => ( ))}
{/* Gateway header strip */}
LL LiteLLM Gateway {t("healthy")}
litellm · {_live.gatewayHost || "127.0.0.1:4000"} · OpenAI-compatible /v1/*
m.metricsSource==="vllm"||m.metricsSource==="llamacpp"||m.metricsSource==="sglang").length} ${t("with live metrics")}`} /> m.metricsSource==="vllm"||m.metricsSource==="llamacpp"||m.metricsSource==="sglang").length} sub={t("vLLM + llama.cpp + SGLang /metrics")} /> m.metricsSource==="vllm"||m.metricsSource==="llamacpp"||m.metricsSource==="sglang").reduce((a,m)=>a+(_live.models[m.id]?_live.models[m.id].tps.now:0),0))} sub={t("t/s · measured sum")} />
{t("Model")}
{t("Throughput")}
{t("TTFT / TPOT")}
{t("KV-cache")}
{t("P50 / P95 / P99")}
{t("Placement · framework")}
{t("State")}
{visible.map((m) => (
setActive(active === m.id ? null : m.id)}>
{m.display} {m.vendor} · {m.params} · {m.quant} · ctx {m.ctx === 0 ? "—" : m.ctx >= 1e6 ? `${(m.ctx/1e6).toFixed(0)}M` : `${(m.ctx/1024).toFixed(0)}K`}
{(m.metricsSource === "vllm" || m.metricsSource === "llamacpp" || m.metricsSource === "sglang") ? ( <>
{_live.models[m.id].tps.now.toFixed(0)}t/s
{/* 并发: tok/s 不带并发数解读不了 (单并发 50t/s vs 4并发 200t/s 截然不同). vLLM/SGLang 暴露 num_requests_running + waiting; llama.cpp 只有 running. */}
{_live.models[m.id].running.now.toFixed(0)} {t("running")} {_live.models[m.id].waiting.now > 0 && ( <> · {_live.models[m.id].waiting.now.toFixed(0)} {t("queued")} )}
) :
{t("no live metrics source")}
· {m.framework} ·
}
{/* TTFT: vLLM 暴露, llama.cpp 不暴露(诚实显—); TPOT: 两者都有 */} {(m.metricsSource === "vllm" || m.metricsSource === "sglang") ? (
{_live.models[m.id].ttft.now.toFixed(0)} ms TTFT
) : m.metricsSource === "llamacpp" ? (
— ms TTFT
) : null} {(m.metricsSource === "vllm" || m.metricsSource === "llamacpp" || m.metricsSource === "sglang") ? (
{_live.models[m.id].tpot.now.toFixed(0)} ms/tok
) : —}
{(m.metricsSource === "vllm" || m.metricsSource === "sglang") ? ( <>
{_live.models[m.id].kv.now.toFixed(1)}%
80 ? "bad" : _live.models[m.id].kv.now > 65 ? "hot" : "violet")}>
) : —}
{(m.metricsSource === "vllm" || m.metricsSource === "sglang") ? <> {m.p50} / {m.p95} / 20000 ? "var(--hot)" : "var(--ink-2)" }}>{m.p99} ms : —}
{m.framework}
{m.nodes.map((nid) => {nid})}
{(m.state === "serving" || m.state === "online") ? <>{t(m.state)} : t(m.state)}
{active === m.id && ( )}
))}
); } function GatewayStat({ label, value, sub }) { return (
{label}
{value}
{sub}
); } function ModelDetail({ model }) { const { t } = useLang(); const ms = _live.models[model.id]; return (
{t("Throughput · last 32 ticks")}
{(model.metricsSource === "vllm" || model.metricsSource === "sglang") ? <> 0 ? ` (+${ms.waiting.now.toFixed(0)} ${t("queued")})` : ""} bar={Math.min(100, ms.running.now * 10)} color={ms.waiting.now > 0 ? "hot" : "ok"} /> 80 ? "bad" : ms.kv.now > 65 ? "hot" : "violet"} /> : model.metricsSource === "llamacpp" ? <> {/* llama.cpp /metrics 暴露 TPOT/throughput/running, 不暴露 TTFT/KV/e2e */}
{t("llama.cpp /metrics does not expose TTFT / KV% / e2e histograms · shown as — honestly")}
:
{model.framework} {t("backend has no Prometheus /metrics endpoint. No live-metrics source → honestly marked, not faked. Model still serves normally via LiteLLM route")} {model.route}
}
{t("Route · ")}{model.route}
{t("Framework")}{model.framework} {t("Port")}:{model.port} {t("Quant")}{model.quant} {t("VRAM")}{model.vram} GB {t("Context")}{model.ctx === 0 ? "—" : model.ctx >= 1e6 ? `${(model.ctx/1e6).toFixed(0)}M tokens` : `${(model.ctx/1024).toFixed(0)}K tokens`} {t("Placement")}{model.nodes.join(", ")}
{model.tags.map((t) => {t})}
); } function modelBtn(primary) { return { appearance: "none", border: "0.5px solid " + (primary ? "transparent" : "var(--line)"), background: primary ? "var(--ink)" : "transparent", color: primary ? "var(--bg)" : "var(--ink)", borderRadius: 7, padding: "7px 12px", font: "500 11.5px var(--display)", letterSpacing: "-.005em", cursor: "pointer", }; } // ── TELEMETRY ────────────────────────────────────────────────────────── function _trendCell(v, suffix = "", digits = 1) { if (v == null) return "—"; return (typeof v === "number" ? v.toFixed(digits) : String(v)) + suffix; } function TelemetrySection() { useLive(); const { t } = useLang(); // HA-derived fields are null when the exporter is absent / sensor stale. // Render the tm-card strip only when at least one field exists; otherwise // the section degrades to its original 2-col grid as if HA never existed. const pw = _live.power || null; const en = _live.env || null; const haAny = (pw && (pw.wallW != null || pw.tokensPerW != null)) || (en && (en.rackTempC != null || en.acOn != null)); const fmt = (v, unit, digits = 1) => v == null ? "—" : (typeof v === "number" ? v.toFixed(digits) : String(v)) + (v == null ? "" : unit); return (
05{t("Telemetry · alerts")}

{t("Signal, not ")}{t("noise.")}

{t("Every request that lands at the gateway, every anomaly the rules engine catches — surfaced as a quiet, structured stream. No paging unless something actually needs you.")}

{haAny && (
{t("Wall power")}
{fmt(pw?.wallW, " W")}
{t("Σ smart-plug · DCGM GPU ")}{fmt(pw?.gpuW, " W")}
{t("Efficiency")}
{fmt(pw?.tokensPerW, "", 2)} {pw?.tokensPerW != null && tok·W⁻¹·s⁻¹}
{t("LiteLLM tokens / wall power")}
{t("Rack")}
{fmt(en?.rackTempC, " °C")} {fmt(en?.rackRH, "%", 0)}
{t("AC ")}{en?.acOn == null ? "—" : en.acOn ? t("on") : t("off")} {en?.acW != null && · {fmt(en.acW, " W")}}
)} {haAny && (
{t("Devices · live power draw")}
{t("Per smart-plug reading from Home Assistant · 15s polled")}
Σ {fmt(pw?.wallW, " W")} {pw?.kwh24h != null && · {t("24h ")} {pw.kwh24h.toFixed(2)} kWh} {pw?.kwh30d != null && · {t("30d ")} {pw.kwh30d.toFixed(2)} kWh} {en?.cabinetHeatProxyC != null && · {t("cabinet ~")} {en.cabinetHeatProxyC.toFixed(1)} °C}
{t("Energy = sliding-window integral of live wall power, independent from HA/Mi Home counters. 24h ≤ 30d strictly by construction; values grow as the series matures.")}
{_NODES.map((n) => { const w = pw?.byNode?.[n.id]; const k24 = pw?.byNode24h?.[n.id]; const k30 = pw?.byNode30d?.[n.id]; const ptemp = en?.byNodePlugTempC?.[n.id]; const has = w != null; const hot = ptemp != null && ptemp >= 50; return ( ); })} {(en?.acW != null || en?.acOn != null) && ( )}
{t("Device")} {t("Type")} {t("Power")} {t("24h")} {t("30d")} {t("Plug °C")} {t("State")}
{n.name} {n.ip} {n.class || t("Compute node")} {has ? w.toFixed(0) + " W" : "—"} {k24 != null ? k24.toFixed(2) + " kWh" : "—"} {k30 != null ? k30.toFixed(2) + " kWh" : "—"} {ptemp != null ? ptemp.toFixed(0) + " °C" : "—"} {has ? ( <>{t("on")} ) : ( {t("no smart plug")} )}
{t("Rack AC")} — {t("Cabinet HVAC")} {en.acW != null ? en.acW.toFixed(0) + " W" : "—"} {en.acKwh24h != null ? en.acKwh24h.toFixed(2) + " kWh" : "—"} {en.acKwh30d != null ? en.acKwh30d.toFixed(2) + " kWh" : "—"} — {en.acOn == null ? t("unknown") : en.acOn ? t("on") : t("off")}
)} {_live.energyTrends && (
{t("Energy trends · A/B for physical changes")}
{t("Day = 06:00–18:00 local · same-window comparison reveals what changes (AC setpoint, sunshade, sensor move) actually moved the bill")}
{/* AC */} {/* Wall */} {/* Cabinet */}
{t("Metric")} {t("24h")} {t("7d")} {t("30d")}
{t("AC energy")} {_trendCell(_live.energyTrends.ac?.last24h?.kwh, " kWh", 2)} {_trendCell(_live.energyTrends.ac?.last7d?.kwh, " kWh", 2)} {_trendCell(_live.energyTrends.ac?.last30d?.kwh, " kWh", 2)}
{t("avg power")} {_trendCell(_live.energyTrends.ac?.last24h?.avgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last7d?.avgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last30d?.avgW, " W", 0)}
↳ {t("day")} (06-18) {_trendCell(_live.energyTrends.ac?.last24h?.dayAvgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last7d?.dayAvgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last30d?.dayAvgW, " W", 0)}
↳ {t("night")} (18-06) {_trendCell(_live.energyTrends.ac?.last24h?.nightAvgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last7d?.nightAvgW, " W", 0)} {_trendCell(_live.energyTrends.ac?.last30d?.nightAvgW, " W", 0)}
{t("Wall avg")} {_trendCell(_live.energyTrends.wall?.last24h?.avgW, " W", 0)} {_trendCell(_live.energyTrends.wall?.last7d?.avgW, " W", 0)} {_trendCell(_live.energyTrends.wall?.last30d?.avgW, " W", 0)}
{t("Cabinet mean")} {_trendCell(_live.energyTrends.cabinet?.last24h?.meanC, " °C", 1)} {_trendCell(_live.energyTrends.cabinet?.last7d?.meanC, " °C", 1)} {_trendCell(_live.energyTrends.cabinet?.last30d?.meanC, " °C", 1)}
{t("min / max")} {_trendCell(_live.energyTrends.cabinet?.last24h?.minC, "", 1)} / {_trendCell(_live.energyTrends.cabinet?.last24h?.maxC, " °C", 1)} {_trendCell(_live.energyTrends.cabinet?.last7d?.minC, "", 1)} / {_trendCell(_live.energyTrends.cabinet?.last7d?.maxC, " °C", 1)} {_trendCell(_live.energyTrends.cabinet?.last30d?.minC, "", 1)} / {_trendCell(_live.energyTrends.cabinet?.last30d?.maxC, " °C", 1)}
{t("samples")} {_live.energyTrends.ac?.last24h?.samples || 0} / 96 {_live.energyTrends.ac?.last7d?.samples || 0} / 672 {_live.energyTrends.ac?.last30d?.samples || 0} / 2880
{t("samples = real data points actually in the window (full = window fully filled). Same value across windows means the series is younger than 24h.")}
)}
Request stream
{t("LiteLLM request log · OSS Postgres")} · {_live.log.length}
{t("streaming")} p50 {_live.cluster.latP50}ms · p95 {_live.cluster.latP95}ms
{_live.log.slice(0, 18).map((e, i) => { const stat = e.status; const cls = stat === "200" ? "ok" : stat === "4xx" ? "warn" : "bad"; return (
{window.AIData.formatTime(e.t)} {stat} {e.meth.split(" ")[1]} → {e.model} {typeof e.lat === "number" ? e.lat + " ms" : "—"}
); })}
Alerts
Last 24 h · 0 paged · 4 informational
{_live.alerts.filter((a) => a.sev === "warn" || a.sev === "hot").length} open
{_live.alerts.map((a, i) => (
{a.msg} {a.sub}
{a.when}
))}
); } // ── FABRIC (network topology) ────────────────────────────────────────── function FabricSection() { useLive(); const { t } = useLang(); const [ref, { w }] = useElementSize(); const H = 360; // 网关节点(default 第一个 role=gateway 或第一个节点) + 推理节点们 const GW = _NODES.find((n) => /gateway/i.test(n.role || "")) || _NODES[0]; const ATL = { x: w * 0.5, y: 70, id: GW.id, label: (GW.name + " · gateway") }; const peers = _NODES.filter((n) => n.id !== GW.id); const peerXs = peers.map((_, i) => w * (peers.length === 1 ? 0.5 : 0.18 + i * (0.64 / Math.max(1, peers.length - 1)))); const sparks = peers.map((n, i) => ({ x: peerXs[i], y: H - 70, id: n.id, label: n.name, })); // Throughput on each link (atlas → spark) const linkLoad = (id) => { const ns = _live.nodes[id]; return Math.min(1, (ns.netIn.now + ns.netOut.now) / 1200); }; // 东西向 CX-7 RoCE/RDMA 真实吞吐 (MB/s),驱动 spark↔spark mesh 强度 const ewLoad = (id) => { const ns = _live.nodes[id]; return Math.min(1, ((ns.rdmaIn ? ns.rdmaIn.now : 0) + (ns.rdmaOut ? ns.rdmaOut.now : 0)) / 4000); }; return (
06{t("Fabric · network")}

{t("The wires ")}{t("between everything.")}

{t("The gateway host peers with every inference node — link intensity & pulse are driven by real node-exporter throughput. Inter-node fabric (RDMA/InfiniBand) is physical topology only (throughput not instrumented by default).")}

{w > 0 && ( {/* spark <-> spark mesh — 强度由真实 RDMA 吞吐驱动 */} {sparks.map((a, i) => sparks.slice(i + 1).map((b, j) => { const ld = Math.max(ewLoad(a.id), ewLoad(b.id)); return ( ); }))} {/* atlas -> sparks */} {sparks.map((s, i) => { const load = linkLoad(s.id); return ( {/* packet pulse */} ); })} {/* atlas node */} {sparks.map((s) => ( n.id === s.id).ip} color="var(--violet)" util={_live.nodes[s.id].gpu.now} /> ))} )}
North-South · 10 GbE {t("East-West · 200 GbE ConnectX-7 RDMA (live)")} {t("North-South pulse ∝ real network throughput")}
); } function NodeBlob({ x, y, label, sub, color, util }) { const r = 24; return ( {util.toFixed(0)}% {label} {sub} ); } // ── COMMAND PALETTE ──────────────────────────────────────────────────── function CmdK({ open, onClose }) { const { t } = useLang(); const [q, setQ] = useState(""); const [idx, setIdx] = useState(0); const items = useMemo(() => { const xs = [ ..._NODES.map((n) => ({ kind: "node", label: n.name, sub: `${n.class} · ${n.ip}`, href: "#nodes" })), ..._MODELS.map((m) => ({ kind: "model", label: m.display, sub: `${m.framework} · ${m.params} · ${m.state}`, href: "#models" })), { kind: "view", label: "Overview", sub: "Section · top of page", href: "#overview" }, { kind: "view", label: "Cluster", sub: "Section · aggregate telemetry", href: "#cluster" }, { kind: "view", label: "Nodes", sub: t("Section · {n} machines", { n: _NODES.length }), href: "#nodes" }, { kind: "view", label: "Models", sub: "Section · LiteLLM gateway", href: "#models" }, { kind: "view", label: "Telemetry", sub: "Section · alerts & log stream", href: "#telemetry" }, { kind: "view", label: "Fabric", sub: "Section · network topology", href: "#fabric" }, ]; if (!q.trim()) return xs; const qq = q.toLowerCase(); return xs.filter((x) => x.label.toLowerCase().includes(qq) || x.sub.toLowerCase().includes(qq)); }, [q]); useEffect(() => { setIdx(0); }, [q]); useEffect(() => { if (!open) return; const onKey = (e) => { if (e.key === "Escape") onClose(); else if (e.key === "ArrowDown") { e.preventDefault(); setIdx((i) => Math.min(i + 1, items.length - 1)); } else if (e.key === "ArrowUp") { e.preventDefault(); setIdx((i) => Math.max(i - 1, 0)); } else if (e.key === "Enter") { const it = items[idx]; if (it) { window.location.hash = it.href; onClose(); } } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [open, items, idx, onClose]); if (!open) return null; return (
e.stopPropagation()}> setQ(e.target.value)} />
{items.slice(0, 8).map((it, i) => (
setIdx(i)} onClick={() => { window.location.hash = it.href; onClose(); }}>
{t(it.label)}
{t(it.sub)}
{it.kind}
))} {items.length === 0 && (
{t("No results")}
)}
); } Object.assign(window, { NodesSection, NodeDetail, ModelsSection, TelemetrySection, FabricSection, CmdK });