Keep monitor alive across nav and speed up status collect.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -50,30 +50,43 @@ function hasOpenPosition(position: Record<string, unknown>): boolean {
|
||||
return OPEN_STATUSES.has(st);
|
||||
}
|
||||
|
||||
/** 页面级快照:整页刷新前保留上次卡片,避免空白等待 */
|
||||
let cachedNodes: NodeCard[] = [];
|
||||
let cachedSseSec = 1;
|
||||
|
||||
export default function MonitorPage() {
|
||||
const [nodes, setNodes] = useState<NodeCard[]>([]);
|
||||
const [nodes, setNodes] = useState<NodeCard[]>(() => cachedNodes);
|
||||
const [err, setErr] = useState("");
|
||||
const [busy, setBusy] = useState<Record<number, string>>({});
|
||||
const [selected, setSelected] = useState<Set<number>>(new Set());
|
||||
const [sseSec, setSseSec] = useState(1);
|
||||
const [liveState, setLiveState] = useState<"connecting" | "live" | "retry">("connecting");
|
||||
const [sseSec, setSseSec] = useState(cachedSseSec);
|
||||
const [liveState, setLiveState] = useState<"connecting" | "live" | "retry">(
|
||||
cachedNodes.length ? "live" : "connecting",
|
||||
);
|
||||
const [detailId, setDetailId] = useState<number | null>(null);
|
||||
|
||||
const applyNodes = useCallback((list: NodeCard[]) => {
|
||||
cachedNodes = list;
|
||||
setNodes(list);
|
||||
}, []);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
try {
|
||||
const r = await apiFetch<{ nodes: NodeCard[] }>("/api/nodes/status/all");
|
||||
setNodes(r.nodes || []);
|
||||
applyNodes(r.nodes || []);
|
||||
setErr("");
|
||||
} catch (ex) {
|
||||
setErr(ex instanceof Error ? ex.message : String(ex));
|
||||
}
|
||||
}, []);
|
||||
}, [applyNodes]);
|
||||
|
||||
useEffect(() => {
|
||||
apiFetch<{ sse_interval_sec?: number }>("/api/auth/me")
|
||||
.then((m) => {
|
||||
if (m.sse_interval_sec && Number(m.sse_interval_sec) > 0) {
|
||||
setSseSec(Number(m.sse_interval_sec));
|
||||
const sec = Number(m.sse_interval_sec);
|
||||
cachedSseSec = sec;
|
||||
setSseSec(sec);
|
||||
}
|
||||
})
|
||||
.catch(() => undefined);
|
||||
@@ -85,7 +98,10 @@ export default function MonitorPage() {
|
||||
let timer: number | undefined;
|
||||
const ac = new AbortController();
|
||||
|
||||
void refresh();
|
||||
// 无缓存时先拉一次;有缓存则等 SSE,避免切页/重挂载双倍打满策略机
|
||||
if (!cachedNodes.length) {
|
||||
void refresh();
|
||||
}
|
||||
|
||||
async function runStream() {
|
||||
while (!cancelled) {
|
||||
@@ -137,7 +153,7 @@ export default function MonitorPage() {
|
||||
if (eventName === "error") {
|
||||
setErr(parsed.detail || "SSE 错误");
|
||||
} else if (parsed.nodes) {
|
||||
setNodes(parsed.nodes);
|
||||
applyNodes(parsed.nodes);
|
||||
setErr("");
|
||||
}
|
||||
} catch {
|
||||
@@ -172,7 +188,7 @@ export default function MonitorPage() {
|
||||
ac.abort();
|
||||
if (timer != null) window.clearTimeout(timer);
|
||||
};
|
||||
}, [refresh]);
|
||||
}, [refresh, applyNodes]);
|
||||
|
||||
async function act(id: number, action: "start" | "pause" | "update" | "login") {
|
||||
if (action === "update") {
|
||||
|
||||
Reference in New Issue
Block a user