refactor: useSchedulesStore.ts

This commit is contained in:
tao.chen
2026-09-02 10:10:41 +08:00
committed by tao.chen
parent a8826f7224
commit 8278cdd8b0
16 changed files with 1581 additions and 1259 deletions
@@ -0,0 +1,118 @@
// Logs slice: per-node-run log fetch + display state.
// toggleLog owns the open/closed toggle and lazily loads content from the
// signed URL on first open.
import type { StateCreator } from "zustand";
import { requireApi } from "./helpers";
import type { LogState } from "./types";
import type { SchedulesStore } from "./useSchedulesStore";
// ---- State ----
export type LogsSliceState = {
openLogNodeRunIds: Set<string>;
logStates: Record<string, LogState>;
};
// ---- Actions ----
export type LogsSliceActions = {
// pure setters
setOpenLogNodeRunIds: (
value: Set<string> | ((current: Set<string>) => Set<string>),
) => void;
setLogStates: (
updater: (current: Record<string, LogState>) => Record<string, LogState>,
) => void;
// mutations
toggleLog: (runId: string, nodeRunId: string) => Promise<void>;
};
// `SchedulesStore` is the combined state+actions of all slices, so `get()`
// returns a fully typed snapshot — no `any` propagation.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const createLogsSlice: StateCreator<SchedulesStore, [], [], LogsSliceState & LogsSliceActions> = (set, get) => ({
// ---- initial state ----
openLogNodeRunIds: new Set(),
logStates: {},
// ---- pure setters ----
setOpenLogNodeRunIds: (value) =>
set((s: any) => ({
openLogNodeRunIds:
typeof value === "function"
? (value as (current: Set<string>) => Set<string>)(
s.openLogNodeRunIds,
)
: value,
})),
setLogStates: (updater) =>
set((s: any) => ({ logStates: updater(s.logStates) })),
// ---- mutations ----
toggleLog: async (runId, nodeRunId) => {
const api = requireApi();
const state = get();
const open = state.openLogNodeRunIds;
if (open.has(nodeRunId)) {
const next = new Set(open);
next.delete(nodeRunId);
set({ openLogNodeRunIds: next });
return;
}
const next = new Set(open);
next.add(nodeRunId);
set({ openLogNodeRunIds: next });
if (state.logStates[nodeRunId]?.content) return;
set((s: any) => ({
logStates: {
...s.logStates,
[nodeRunId]: {
loading: true,
content: null,
fileName: null,
error: null,
},
},
}));
try {
const artifacts = await api.getScheduleNodeRunArtifacts(runId, nodeRunId);
if (!artifacts.log) throw new Error("本次节点执行没有可用日志");
const response = await fetch(artifacts.log.url, {
credentials: "same-origin",
cache: "no-store",
});
if (!response.ok) {
throw new Error(`日志读取失败(HTTP ${response.status}`);
}
const content = await response.text();
set((s: any) => ({
logStates: {
...s.logStates,
[nodeRunId]: {
loading: false,
content,
fileName: artifacts.log?.file_name ?? null,
error: null,
},
},
}));
} catch (error) {
set((s: any) => ({
logStates: {
...s.logStates,
[nodeRunId]: {
loading: false,
content: null,
fileName: null,
error: error instanceof Error ? error.message : "日志读取失败",
},
},
}));
}
},
});