import { produce } from "immer"; import { create } from "zustand"; import { type WorkflowModel, type WorkflowNode, type WorkflowNodeConfigForStart, addBranch, addNode, duplicateBranch, duplicateNode, getOutputBeforeNodeId, removeBranch, removeNode, updateNode, } from "@/domain/workflow"; import { get as getWorkflow, save as saveWorkflow } from "@/repository/workflow"; export type WorkflowState = { workflow: WorkflowModel; initialized: boolean; init(id: string): void; setBaseInfo: (name: string, description: string) => void; setEnabled(enabled: boolean): void; release(): void; discard(): void; destroy(): void; addNode: (node: WorkflowNode, previousNodeId: string) => void; duplicateNode: (node: WorkflowNode) => void; updateNode: (node: WorkflowNode) => void; removeNode: (node: WorkflowNode) => void; addBranch: (branchId: string) => void; duplicateBranch: (branchId: string, index: number) => void; removeBranch: (branchId: string, index: number) => void; getWorkflowOuptutBeforeId: (nodeId: string, typeFilter?: string | string[]) => WorkflowNode[]; }; export const useWorkflowStore = create((set, get) => ({ workflow: {} as WorkflowModel, initialized: false, init: async (id: string) => { const data = await getWorkflow(id); set({ workflow: data, initialized: true, }); }, destroy: () => { set({ workflow: {} as WorkflowModel, initialized: false, }); }, setBaseInfo: async (name: string, description: string) => { if (!get().initialized) throw "Workflow not initialized yet"; const resp = await saveWorkflow({ id: get().workflow.id!, name: name || "", description: description || "", }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.name = resp.name; draft.description = resp.description; }), }; }); }, setEnabled: async (enabled: boolean) => { if (!get().initialized) throw "Workflow not initialized yet"; const resp = await saveWorkflow({ id: get().workflow.id!, enabled: enabled, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.enabled = resp.enabled; }), }; }); }, release: async () => { if (!get().initialized) throw "Workflow not initialized yet"; const root = get().workflow.draft!; const startConfig = root.config as WorkflowNodeConfigForStart; const resp = await saveWorkflow({ id: get().workflow.id!, trigger: startConfig.trigger, triggerCron: startConfig.triggerCron, content: root, hasDraft: false, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.trigger = resp.trigger; draft.triggerCron = resp.triggerCron; draft.content = resp.content; draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, discard: async () => { if (!get().initialized) throw "Workflow not initialized yet"; const root = get().workflow.content!; const startConfig = root.config as WorkflowNodeConfigForStart; const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: false, trigger: startConfig.trigger, triggerCron: startConfig.triggerCron, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.trigger = resp.trigger; draft.triggerCron = resp.triggerCron; draft.content = resp.content; draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, addNode: async (node: WorkflowNode, previousNodeId: string) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = addNode(get().workflow.draft!, node, previousNodeId); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, duplicateNode: async (node: WorkflowNode) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = duplicateNode(get().workflow.draft!, node); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, updateNode: async (node: WorkflowNode) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = updateNode(get().workflow.draft!, node); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, removeNode: async (node: WorkflowNode) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = removeNode(get().workflow.draft!, node.id); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, addBranch: async (branchId: string) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = addBranch(get().workflow.draft!, branchId); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, duplicateBranch: async (branchId: string, index: number) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = duplicateBranch(get().workflow.draft!, branchId, index); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, removeBranch: async (branchId: string, index: number) => { if (!get().initialized) throw "Workflow not initialized yet"; const root = removeBranch(get().workflow.draft!, branchId, index); const resp = await saveWorkflow({ id: get().workflow.id!, draft: root, hasDraft: true, }); set((state: WorkflowState) => { return { workflow: produce(state.workflow, (draft) => { draft.draft = resp.draft; draft.hasDraft = resp.hasDraft; }), }; }); }, getWorkflowOuptutBeforeId: (nodeId: string, typeFilter?: string | string[]) => { return getOutputBeforeNodeId(get().workflow.draft as WorkflowNode, nodeId, typeFilter); }, }));