126 lines
3.6 KiB
TypeScript
126 lines
3.6 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, options) => {
|
|
event?.stopPropagation();
|
|
const buffer = get().pythonEditorBuffers[id];
|
|
if (buffer?.dirty && !buffer.saving && !options?.discardDirty) {
|
|
return false;
|
|
}
|
|
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 };
|
|
});
|
|
return true;
|
|
},
|
|
|
|
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);
|
|
},
|
|
};
|
|
}; |