90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
// ---- previewSlice ----
|
|
//
|
|
// 拥有 previewKey / previewCode / previewCodeSize / previewLoading / previewError。
|
|
// Action: loadPreview (用 AbortController 取消旧请求 + request-id 序列号忽略过期响应)。
|
|
|
|
import type { StateCreator } from "zustand";
|
|
|
|
import {
|
|
bumpPreviewRequest,
|
|
getPreviewController,
|
|
getPreviewRequest,
|
|
setPreviewController,
|
|
} from "./helpers";
|
|
|
|
import type {
|
|
PreviewSliceActions,
|
|
PreviewSliceState,
|
|
} from "./types";
|
|
import type { ScriptWorkspaceStore } from "./useScriptWorkspaceStore";
|
|
|
|
export const createPreviewSlice: StateCreator<
|
|
ScriptWorkspaceStore,
|
|
[],
|
|
[],
|
|
PreviewSliceState & PreviewSliceActions
|
|
> = (set) => {
|
|
const initial: PreviewSliceState = {
|
|
previewKey: null,
|
|
previewCode: null,
|
|
previewCodeSize: null,
|
|
previewLoading: false,
|
|
previewError: null,
|
|
};
|
|
|
|
return {
|
|
...initial,
|
|
|
|
loadPreview: async (workspaceId, filePath) => {
|
|
const existing = getPreviewController();
|
|
if (existing) {
|
|
existing.abort();
|
|
}
|
|
const requestId = bumpPreviewRequest();
|
|
const previewKey = `${workspaceId}::${filePath}`;
|
|
|
|
set({ previewKey, previewLoading: true, previewError: null });
|
|
|
|
const controller = new AbortController();
|
|
setPreviewController(controller);
|
|
|
|
try {
|
|
const url =
|
|
`/jupyter/${workspaceId}/api/contents/${filePath}` +
|
|
`?type=file&content=1&hash=1&format=text`;
|
|
const response = await fetch(url, {
|
|
signal: controller.signal,
|
|
credentials: "include",
|
|
cache: "no-store",
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to load file: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
if (getPreviewRequest() !== requestId) return;
|
|
set({
|
|
previewKey,
|
|
previewCode: data.content ?? "",
|
|
previewCodeSize: data.size ?? 0,
|
|
previewLoading: false,
|
|
previewError: null,
|
|
});
|
|
} catch (error) {
|
|
if (getPreviewRequest() !== requestId) return;
|
|
if (error instanceof Error && error.name === "AbortError") return;
|
|
set({
|
|
previewKey,
|
|
previewCode: null,
|
|
previewCodeSize: null,
|
|
previewLoading: false,
|
|
previewError:
|
|
error instanceof Error ? error.message : "加载预览失败",
|
|
});
|
|
} finally {
|
|
if (getPreviewRequest() === requestId) {
|
|
setPreviewController(null);
|
|
}
|
|
}
|
|
},
|
|
};
|
|
}; |