feat: undo/redo for workflow editor (#3927)

Co-authored-by: StyleZhang <jasonapring2015@outlook.com>
This commit is contained in:
Pascal M
2024-06-26 08:37:12 +02:00
committed by GitHub
parent d0fe56a98e
commit af9448e6f2
38 changed files with 2049 additions and 778 deletions

View File

@@ -42,18 +42,21 @@ import { CUSTOM_NOTE_NODE } from '../note-node/constants'
import type { IterationNodeType } from '../nodes/iteration/types'
import type { VariableAssignerNodeType } from '../nodes/variable-assigner/types'
import { useNodeIterationInteractions } from '../nodes/iteration/use-interactions'
import { useWorkflowHistoryStore } from '../workflow-history-store'
import { useNodesSyncDraft } from './use-nodes-sync-draft'
import { useHelpline } from './use-helpline'
import {
useNodesReadOnly,
useWorkflow,
} from './use-workflow'
import { WorkflowHistoryEvent, useWorkflowHistory } from './use-workflow-history'
export const useNodesInteractions = () => {
const { t } = useTranslation()
const store = useStoreApi()
const workflowStore = useWorkflowStore()
const reactflow = useReactFlow()
const { store: workflowHistoryStore } = useWorkflowHistoryStore()
const { handleSyncWorkflowDraft } = useNodesSyncDraft()
const {
getAfterNodesInSameBranch,
@@ -66,6 +69,8 @@ export const useNodesInteractions = () => {
} = useNodeIterationInteractions()
const dragNodeStartPosition = useRef({ x: 0, y: 0 } as { x: number; y: number })
const { saveStateToHistory, undo, redo } = useWorkflowHistory()
const handleNodeDragStart = useCallback<NodeDragHandler>((_, node) => {
workflowStore.setState({ nodeAnimation: false })
@@ -137,8 +142,13 @@ export const useNodesInteractions = () => {
setHelpLineHorizontal()
setHelpLineVertical()
handleSyncWorkflowDraft()
if (x !== 0 && y !== 0) {
// selecting a note will trigger a drag stop event with x and y as 0
saveStateToHistory(WorkflowHistoryEvent.NodeDragStop)
}
}
}, [handleSyncWorkflowDraft, workflowStore, getNodesReadOnly])
}, [workflowStore, getNodesReadOnly, saveStateToHistory, handleSyncWorkflowDraft])
const handleNodeEnter = useCallback<NodeMouseHandler>((_, node) => {
if (getNodesReadOnly())
@@ -359,8 +369,10 @@ export const useNodesInteractions = () => {
return filtered
})
setEdges(newEdges)
handleSyncWorkflowDraft()
}, [store, handleSyncWorkflowDraft, getNodesReadOnly])
saveStateToHistory(WorkflowHistoryEvent.NodeConnect)
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
const handleNodeConnectStart = useCallback<OnConnectStart>((_, { nodeId, handleType, handleId }) => {
if (getNodesReadOnly())
@@ -544,7 +556,13 @@ export const useNodesInteractions = () => {
})
setEdges(newEdges)
handleSyncWorkflowDraft()
}, [store, handleSyncWorkflowDraft, getNodesReadOnly, workflowStore, t])
if (currentNode.type === 'custom-note')
saveStateToHistory(WorkflowHistoryEvent.NoteDelete)
else
saveStateToHistory(WorkflowHistoryEvent.NodeDelete)
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, t])
const handleNodeAdd = useCallback<OnNodeAdd>((
{
@@ -877,7 +895,8 @@ export const useNodesInteractions = () => {
setEdges(newEdges)
}
handleSyncWorkflowDraft()
}, [store, workflowStore, handleSyncWorkflowDraft, getAfterNodesInSameBranch, getNodesReadOnly, t])
saveStateToHistory(WorkflowHistoryEvent.NodeAdd)
}, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory, workflowStore, getAfterNodesInSameBranch])
const handleNodeChange = useCallback((
currentNodeId: string,
@@ -955,7 +974,9 @@ export const useNodesInteractions = () => {
})
setEdges(newEdges)
handleSyncWorkflowDraft()
}, [store, handleSyncWorkflowDraft, getNodesReadOnly, t])
saveStateToHistory(WorkflowHistoryEvent.NodeChange)
}, [getNodesReadOnly, store, t, handleSyncWorkflowDraft, saveStateToHistory])
const handleNodeCancelRunningStatus = useCallback(() => {
const {
@@ -1107,9 +1128,10 @@ export const useNodesInteractions = () => {
})
setNodes([...nodes, ...nodesToPaste])
saveStateToHistory(WorkflowHistoryEvent.NodePaste)
handleSyncWorkflowDraft()
}
}, [getNodesReadOnly, store, workflowStore, handleSyncWorkflowDraft, reactflow, handleNodeIterationChildrenCopy])
}, [getNodesReadOnly, workflowStore, store, reactflow, saveStateToHistory, handleSyncWorkflowDraft, handleNodeIterationChildrenCopy])
const handleNodesDuplicate = useCallback(() => {
if (getNodesReadOnly())
@@ -1208,7 +1230,52 @@ export const useNodesInteractions = () => {
})
setNodes(newNodes)
handleSyncWorkflowDraft()
}, [store, getNodesReadOnly, handleSyncWorkflowDraft])
saveStateToHistory(WorkflowHistoryEvent.NodeResize)
}, [getNodesReadOnly, store, handleSyncWorkflowDraft, saveStateToHistory])
const handleHistoryBack = useCallback(() => {
if (getNodesReadOnly())
return
const {
shortcutsDisabled,
} = workflowStore.getState()
if (shortcutsDisabled)
return
const { setEdges, setNodes } = store.getState()
undo()
const { edges, nodes } = workflowHistoryStore.getState()
if (edges.length === 0 && nodes.length === 0)
return
setEdges(edges)
setNodes(nodes)
}, [store, undo, workflowHistoryStore, workflowStore, getNodesReadOnly])
const handleHistoryForward = useCallback(() => {
if (getNodesReadOnly())
return
const {
shortcutsDisabled,
} = workflowStore.getState()
if (shortcutsDisabled)
return
const { setEdges, setNodes } = store.getState()
redo()
const { edges, nodes } = workflowHistoryStore.getState()
if (edges.length === 0 && nodes.length === 0)
return
setEdges(edges)
setNodes(nodes)
}, [redo, store, workflowHistoryStore, workflowStore, getNodesReadOnly])
return {
handleNodeDragStart,
@@ -1232,5 +1299,7 @@ export const useNodesInteractions = () => {
handleNodesDuplicate,
handleNodesDelete,
handleNodeResize,
handleHistoryBack,
handleHistoryForward,
}
}