mirror of
http://112.124.100.131/huang.ze/ebiz-dify-ai.git
synced 2025-12-14 21:36:51 +08:00
feat: undo/redo for workflow editor (#3927)
Co-authored-by: StyleZhang <jasonapring2015@outlook.com>
This commit is contained in:
120
web/app/components/workflow/workflow-history-store.tsx
Normal file
120
web/app/components/workflow/workflow-history-store.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { type ReactNode, createContext, useContext, useMemo, useState } from 'react'
|
||||
import { type StoreApi, create } from 'zustand'
|
||||
import { type TemporalState, temporal } from 'zundo'
|
||||
import isDeepEqual from 'fast-deep-equal'
|
||||
import type { Edge, Node } from './types'
|
||||
import type { WorkflowHistoryEvent } from './hooks'
|
||||
|
||||
export const WorkflowHistoryStoreContext = createContext<WorkflowHistoryStoreContextType>({ store: null, shortcutsEnabled: true, setShortcutsEnabled: () => {} })
|
||||
export const Provider = WorkflowHistoryStoreContext.Provider
|
||||
|
||||
export function WorkflowHistoryProvider({
|
||||
nodes,
|
||||
edges,
|
||||
children,
|
||||
}: WorkflowWithHistoryProviderProps) {
|
||||
const [shortcutsEnabled, setShortcutsEnabled] = useState(true)
|
||||
const [store] = useState(() =>
|
||||
createStore({
|
||||
nodes,
|
||||
edges,
|
||||
}),
|
||||
)
|
||||
|
||||
const contextValue = {
|
||||
store,
|
||||
shortcutsEnabled,
|
||||
setShortcutsEnabled,
|
||||
}
|
||||
|
||||
return (
|
||||
<Provider value={contextValue}>
|
||||
{children}
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useWorkflowHistoryStore() {
|
||||
const {
|
||||
store,
|
||||
shortcutsEnabled,
|
||||
setShortcutsEnabled,
|
||||
} = useContext(WorkflowHistoryStoreContext)
|
||||
if (store === null)
|
||||
throw new Error('useWorkflowHistoryStoreApi must be used within a WorkflowHistoryProvider')
|
||||
|
||||
return {
|
||||
store: useMemo(
|
||||
() => ({
|
||||
getState: store.getState,
|
||||
setState: (state: WorkflowHistoryState) => {
|
||||
store.setState({
|
||||
workflowHistoryEvent: state.workflowHistoryEvent,
|
||||
nodes: state.nodes.map((node: Node) => ({ ...node, data: { ...node.data, selected: false } })),
|
||||
edges: state.edges.map((edge: Edge) => ({ ...edge, selected: false }) as Edge),
|
||||
})
|
||||
},
|
||||
subscribe: store.subscribe,
|
||||
temporal: store.temporal,
|
||||
}),
|
||||
[store],
|
||||
),
|
||||
shortcutsEnabled,
|
||||
setShortcutsEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
function createStore({
|
||||
nodes: storeNodes,
|
||||
edges: storeEdges,
|
||||
}: {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
}): WorkflowHistoryStoreApi {
|
||||
const store = create(temporal<WorkflowHistoryState>(
|
||||
(set, get) => {
|
||||
return {
|
||||
workflowHistoryEvent: undefined,
|
||||
nodes: storeNodes,
|
||||
edges: storeEdges,
|
||||
getNodes: () => get().nodes,
|
||||
setNodes: (nodes: Node[]) => set({ nodes }),
|
||||
setEdges: (edges: Edge[]) => set({ edges }),
|
||||
}
|
||||
},
|
||||
{
|
||||
equality: (pastState, currentState) =>
|
||||
isDeepEqual(pastState, currentState),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
export type WorkflowHistoryStore = {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
workflowHistoryEvent: WorkflowHistoryEvent | undefined
|
||||
}
|
||||
|
||||
export type WorkflowHistoryActions = {
|
||||
setNodes?: (nodes: Node[]) => void
|
||||
setEdges?: (edges: Edge[]) => void
|
||||
}
|
||||
|
||||
export type WorkflowHistoryState = WorkflowHistoryStore & WorkflowHistoryActions
|
||||
|
||||
type WorkflowHistoryStoreContextType = {
|
||||
store: ReturnType<typeof createStore> | null
|
||||
shortcutsEnabled: boolean
|
||||
setShortcutsEnabled: (enabled: boolean) => void
|
||||
}
|
||||
|
||||
export type WorkflowHistoryStoreApi = StoreApi<WorkflowHistoryState> & { temporal: StoreApi<TemporalState<WorkflowHistoryState>> }
|
||||
|
||||
export type WorkflowWithHistoryProviderProps = {
|
||||
nodes: Node[]
|
||||
edges: Edge[]
|
||||
children: ReactNode
|
||||
}
|
||||
Reference in New Issue
Block a user