233 lines
6.0 KiB
TypeScript
233 lines
6.0 KiB
TypeScript
import { create } from "zustand";
|
|
|
|
import type {
|
|
ScriptItem,
|
|
ScriptType,
|
|
StableVersion,
|
|
Visibility,
|
|
} from "../../../services/api";
|
|
|
|
export type ToastTone = "success" | "error" | "info";
|
|
export type ToastState = {
|
|
tone: ToastTone;
|
|
message: string;
|
|
};
|
|
|
|
export type NewScriptForm = {
|
|
name: string;
|
|
scriptType: ScriptType;
|
|
visibility: Visibility;
|
|
parentPath: string;
|
|
};
|
|
|
|
export type ContextMenuState = {
|
|
x: number;
|
|
y: number;
|
|
kind: "root" | "directory" | "file";
|
|
path: string;
|
|
script?: ScriptItem;
|
|
};
|
|
|
|
export type FolderDialogState = {
|
|
open: boolean;
|
|
parentPath: string;
|
|
name: string;
|
|
busy: boolean;
|
|
};
|
|
|
|
export type PublishDialogState = {
|
|
target: ScriptItem | null;
|
|
releaseNote: string;
|
|
visibility: Visibility;
|
|
publishing: boolean;
|
|
publishedVersion: StableVersion | null;
|
|
};
|
|
|
|
export type UploadState = {
|
|
parentPath: string;
|
|
uploading: boolean;
|
|
};
|
|
|
|
export const initialCreateForm: NewScriptForm = {
|
|
name: "",
|
|
scriptType: "notebook",
|
|
visibility: "workspace",
|
|
parentPath: "",
|
|
};
|
|
|
|
type UiState = {
|
|
toast: ToastState | null;
|
|
createDialog: {
|
|
open: boolean;
|
|
creating: boolean;
|
|
form: NewScriptForm;
|
|
};
|
|
folderDialog: FolderDialogState;
|
|
contextMenu: ContextMenuState | null;
|
|
workspaceMenuOpen: boolean;
|
|
upload: UploadState;
|
|
publish: PublishDialogState;
|
|
|
|
// toast
|
|
pushToast: (toast: ToastState) => void;
|
|
dismissToast: () => void;
|
|
|
|
// create dialog
|
|
openCreateDialog: (parentPath?: string, scriptType?: ScriptType) => void;
|
|
closeCreateDialog: () => void;
|
|
setCreateForm: (form: NewScriptForm) => void;
|
|
setCreating: (creating: boolean) => void;
|
|
|
|
// folder dialog
|
|
openFolderDialog: (parentPath?: string) => void;
|
|
closeFolderDialog: () => void;
|
|
setFolderName: (name: string) => void;
|
|
setFolderBusy: (busy: boolean) => void;
|
|
|
|
// context menu
|
|
showContextMenu: (
|
|
event: { clientX: number; clientY: number; preventDefault: () => void; stopPropagation: () => void },
|
|
target: Omit<ContextMenuState, "x" | "y">,
|
|
) => void;
|
|
closeContextMenu: () => void;
|
|
|
|
// workspace menu (topbar)
|
|
setWorkspaceMenuOpen: (open: boolean) => void;
|
|
|
|
// upload
|
|
chooseUpload: (parentPath?: string) => void;
|
|
setUploading: (uploading: boolean) => void;
|
|
setUploadParentPath: (parentPath: string) => void;
|
|
|
|
// publish dialog
|
|
openPublishDialog: (script: ScriptItem) => void;
|
|
closePublishDialog: () => void;
|
|
setReleaseNote: (note: string) => void;
|
|
setPublishVisibility: (visibility: Visibility) => void;
|
|
setPublishing: (publishing: boolean) => void;
|
|
setPublishedVersion: (version: StableVersion) => void;
|
|
clearPublishedVersion: () => void;
|
|
};
|
|
|
|
export const useUiStore = create<UiState>((set) => ({
|
|
toast: null,
|
|
createDialog: {
|
|
open: false,
|
|
creating: false,
|
|
form: initialCreateForm,
|
|
},
|
|
folderDialog: {
|
|
open: false,
|
|
parentPath: "",
|
|
name: "",
|
|
busy: false,
|
|
},
|
|
contextMenu: null,
|
|
workspaceMenuOpen: false,
|
|
upload: {
|
|
parentPath: "",
|
|
uploading: false,
|
|
},
|
|
publish: {
|
|
target: null,
|
|
releaseNote: "",
|
|
visibility: "workspace",
|
|
publishing: false,
|
|
publishedVersion: null,
|
|
},
|
|
|
|
pushToast: (toast) => set({ toast }),
|
|
dismissToast: () => set({ toast: null }),
|
|
|
|
openCreateDialog: (parentPath = "", scriptType = "notebook") =>
|
|
set((state) => ({
|
|
contextMenu: null,
|
|
createDialog: {
|
|
open: true,
|
|
creating: false,
|
|
form: { ...initialCreateForm, parentPath, scriptType },
|
|
},
|
|
})),
|
|
closeCreateDialog: () =>
|
|
set((state) => ({
|
|
createDialog: { ...state.createDialog, open: false },
|
|
})),
|
|
setCreateForm: (form) =>
|
|
set((state) => ({ createDialog: { ...state.createDialog, form } })),
|
|
setCreating: (creating) =>
|
|
set((state) => ({ createDialog: { ...state.createDialog, creating } })),
|
|
|
|
openFolderDialog: (parentPath = "") =>
|
|
set((state) => ({
|
|
contextMenu: null,
|
|
folderDialog: {
|
|
open: true,
|
|
parentPath,
|
|
name: "",
|
|
busy: false,
|
|
},
|
|
})),
|
|
closeFolderDialog: () =>
|
|
set((state) => ({
|
|
folderDialog: { ...state.folderDialog, open: false },
|
|
})),
|
|
setFolderName: (name) =>
|
|
set((state) => ({ folderDialog: { ...state.folderDialog, name } })),
|
|
setFolderBusy: (busy) =>
|
|
set((state) => ({ folderDialog: { ...state.folderDialog, busy } })),
|
|
|
|
showContextMenu: (event, target) => {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
const width = 188;
|
|
const height = target.kind === "file" ? 92 : 190;
|
|
set({
|
|
contextMenu: {
|
|
...target,
|
|
x: Math.min(event.clientX, window.innerWidth - width - 8),
|
|
y: Math.min(event.clientY, window.innerHeight - height - 8),
|
|
},
|
|
});
|
|
},
|
|
closeContextMenu: () => set({ contextMenu: null }),
|
|
|
|
setWorkspaceMenuOpen: (open) => set({ workspaceMenuOpen: open }),
|
|
|
|
chooseUpload: (parentPath = "") =>
|
|
set((state) => ({
|
|
contextMenu: null,
|
|
upload: { ...state.upload, parentPath },
|
|
})),
|
|
setUploading: (uploading) =>
|
|
set((state) => ({ upload: { ...state.upload, uploading } })),
|
|
setUploadParentPath: (parentPath) =>
|
|
set((state) => ({ upload: { ...state.upload, parentPath } })),
|
|
|
|
openPublishDialog: (script) =>
|
|
set((state) => ({
|
|
publish: {
|
|
...state.publish,
|
|
target: script,
|
|
releaseNote: "",
|
|
visibility: script.visibility === "private" ? "private" : "workspace",
|
|
},
|
|
})),
|
|
closePublishDialog: () =>
|
|
set((state) => ({ publish: { ...state.publish, target: null } })),
|
|
setReleaseNote: (note) =>
|
|
set((state) => ({ publish: { ...state.publish, releaseNote: note } })),
|
|
setPublishVisibility: (visibility) =>
|
|
set((state) => ({ publish: { ...state.publish, visibility } })),
|
|
setPublishing: (publishing) =>
|
|
set((state) => ({ publish: { ...state.publish, publishing } })),
|
|
setPublishedVersion: (version) =>
|
|
set((state) => ({
|
|
publish: {
|
|
...state.publish,
|
|
target: null,
|
|
publishedVersion: version,
|
|
},
|
|
})),
|
|
clearPublishedVersion: () =>
|
|
set((state) => ({ publish: { ...state.publish, publishedVersion: null } })),
|
|
})); |