feat: preview components
This commit is contained in:
@@ -8,7 +8,7 @@ import type {
|
||||
Visibility,
|
||||
WorkspaceBoundApi,
|
||||
WorkspaceDirectory,
|
||||
} from "../../../services/api";
|
||||
} from "~/services/api";
|
||||
|
||||
import type { NewScriptForm } from "./uiStore";
|
||||
import { useUiStore } from "./uiStore";
|
||||
@@ -27,6 +27,8 @@ let _editSession: ActiveEditSession | null = null;
|
||||
let _editorOpening = false;
|
||||
let _editorOpenRequest = 0;
|
||||
let _api: WorkspaceBoundApi | null = null;
|
||||
let _previewController: AbortController | null = null;
|
||||
let _previewRequest = 0;
|
||||
|
||||
export const bindScriptWorkspaceApi = (api: WorkspaceBoundApi | null) => {
|
||||
_api = api;
|
||||
@@ -60,6 +62,12 @@ type State = {
|
||||
latestVersion: LatestVersion | null;
|
||||
latestVersionLoading: boolean;
|
||||
|
||||
previewKey: string | null;
|
||||
previewCode: string | null;
|
||||
previewCodeSize: number | null;
|
||||
previewLoading: boolean;
|
||||
previewError: string | null;
|
||||
|
||||
// actions
|
||||
setApiOnline: (online: boolean) => void;
|
||||
setKeyword: (keyword: string) => void;
|
||||
@@ -72,6 +80,7 @@ type State = {
|
||||
openScriptEditor: (script: ScriptItem, showToast?: boolean) => Promise<void>;
|
||||
endEditing: (closeTabFlag?: boolean, showToast?: boolean) => Promise<void>;
|
||||
loadLatestVersion: (scriptId: string) => Promise<void>;
|
||||
loadPreview: (workspaceId: string, filePath: string) => Promise<void>;
|
||||
createScript: (form: NewScriptForm) => Promise<ScriptItem | null>;
|
||||
uploadScripts: (files: File[], parentPath: string) => Promise<void>;
|
||||
createFolder: (name: string, parentPath: string) => Promise<void>;
|
||||
@@ -132,10 +141,21 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
|
||||
latestVersion: null,
|
||||
latestVersionLoading: false,
|
||||
|
||||
previewKey: null,
|
||||
previewCode: null,
|
||||
previewCodeSize: null,
|
||||
previewLoading: false,
|
||||
previewError: null,
|
||||
|
||||
setApiOnline: (online) => set({ apiOnline: online }),
|
||||
setKeyword: (keyword) => set({ keyword }),
|
||||
|
||||
reset: () => {
|
||||
if (_previewController) {
|
||||
_previewController.abort();
|
||||
_previewController = null;
|
||||
}
|
||||
_previewRequest += 1;
|
||||
_selectedId = null;
|
||||
_editSession = null;
|
||||
editSessionHandle.current = null;
|
||||
@@ -150,6 +170,11 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
|
||||
editorOpenError: null,
|
||||
latestVersion: null,
|
||||
latestVersionLoading: false,
|
||||
previewKey: null,
|
||||
previewCode: null,
|
||||
previewCodeSize: null,
|
||||
previewLoading: false,
|
||||
previewError: null,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -390,6 +415,58 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
|
||||
}
|
||||
},
|
||||
|
||||
loadPreview: async (workspaceId, filePath) => {
|
||||
if (_previewController) {
|
||||
_previewController.abort();
|
||||
}
|
||||
_previewRequest += 1;
|
||||
const requestId = _previewRequest;
|
||||
const previewKey = `${workspaceId}::${filePath}`;
|
||||
|
||||
set({ previewKey, previewLoading: true, previewError: null });
|
||||
|
||||
const controller = new AbortController();
|
||||
_previewController = 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 (_previewRequest !== requestId) return;
|
||||
set({
|
||||
previewKey,
|
||||
previewCode: data.content ?? "",
|
||||
previewCodeSize: data.size ?? 0,
|
||||
previewLoading: false,
|
||||
previewError: null,
|
||||
});
|
||||
} catch (error) {
|
||||
if (_previewRequest !== 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 (_previewRequest === requestId) {
|
||||
_previewController = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createScript: async (form) => {
|
||||
const api = requireApi();
|
||||
const suffix = form.scriptType === "notebook" ? ".ipynb" : ".py";
|
||||
@@ -666,4 +743,4 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
|
||||
}
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user