Files
model-platform/frontend/app/features/platform/state/selectionSlice.ts
T

128 lines
3.7 KiB
TypeScript

// ---- selectionSlice ----
//
// 拥有 selectedId / openTabIds / keyword + 选择/标签页/搜索关键词相关 action。
// cross-slice 依赖: closeTab 调用 pythonEditorSlice.exitPythonEditor +
// editSessionSlice.endEditing + helpers.sessionCache;
// switchTab 触发 pythonEditorSlice.savePythonEditor + helpers.applyEditSessionState
// (恢复缓存中的 editSession);
// openPublishDialog 委托 uiStore。
import type { StateCreator } from "zustand";
import type { ScriptItem } from "~/services/api";
import {
applyEditSessionState,
bumpEditorOpenRequest,
getSelectedId,
sessionCache,
setSelectedId,
} from "./helpers";
import { useUiStore } from "./uiStore";
import type {
SelectionSliceActions,
SelectionSliceState,
} from "./types";
import type { ScriptWorkspaceStore } from "./useScriptWorkspaceStore";
export const createSelectionSlice: StateCreator<
ScriptWorkspaceStore,
[],
[],
SelectionSliceState & SelectionSliceActions
> = (set, get) => {
const initial: SelectionSliceState = {
selectedId: null,
openTabIds: [],
keyword: "",
};
return {
...initial,
setKeyword: (keyword) => set({ keyword }),
selectScript: (id) => {
setSelectedId(id);
set({ selectedId: id });
},
openTab: (id) => {
const current = getSelectedId();
if (current !== id) {
bumpEditorOpenRequest();
set({ editorOpenError: null });
}
setSelectedId(id);
set((state) => ({
selectedId: id,
openTabIds: state.openTabIds.includes(id)
? state.openTabIds
: [...state.openTabIds, id],
}));
},
closeTab: async (id, event) => {
event?.stopPropagation();
const buffer = get().pythonEditorBuffers[id];
if (buffer?.dirty && !buffer.saving) {
const name =
get().scripts.find((s) => s.script_id === id)?.script_name ?? "该脚本";
const ok = window.confirm(`当前脚本有未保存修改,确定关闭 "${name}" 吗?`);
if (!ok) return;
}
if (buffer) {
get().exitPythonEditor(id);
}
const editSession = get().editSession;
if (editSession?.script_id === id) {
await get().endEditing(false, false);
}
sessionCache.delete(id);
set((state) => {
const index = state.openTabIds.indexOf(id);
if (index === -1) return {};
const newTabs = state.openTabIds.filter((tabId) => tabId !== id);
let nextSelected = state.selectedId;
if (state.selectedId === id) {
const nextId = newTabs[index] ?? newTabs[index - 1] ?? null;
setSelectedId(nextId);
nextSelected = nextId;
}
return { openTabIds: newTabs, selectedId: nextSelected };
});
},
switchTab: (id) => {
const current = get().selectedId;
if (current && current !== id) {
const curBuffer = get().pythonEditorBuffers[current];
if (curBuffer?.dirty && !curBuffer.saving) {
void get().savePythonEditor(current);
}
}
const selected = getSelectedId();
if (selected !== id) {
bumpEditorOpenRequest();
set({ editorOpenError: null });
}
setSelectedId(id);
set({ selectedId: id });
const cached = sessionCache.get(id);
if (cached) {
cached.lastActiveTime = Date.now();
// set 来自 StateCreator, 接受 Partial<ScriptWorkspaceStore>。
// applyEditSessionState 接受更窄的 partial;通过函数协变兼容。
applyEditSessionState(
(p) => set(p),
cached.session,
cached.jupyterUrl,
);
}
},
openPublishDialog: (script: ScriptItem) => {
useUiStore.getState().openPublishDialog(script);
},
};
};