|
@@ -715,6 +715,108 @@ export const useNodesInteractions = () => {
|
|
|
handleSyncWorkflowDraft()
|
|
|
}, [store, handleSyncWorkflowDraft, getNodesReadOnly, t])
|
|
|
|
|
|
+ const handleNodeCopySelected = useCallback((): undefined | Node[] => {
|
|
|
+ if (getNodesReadOnly())
|
|
|
+ return
|
|
|
+
|
|
|
+ const {
|
|
|
+ setClipboardElements,
|
|
|
+ } = workflowStore.getState()
|
|
|
+
|
|
|
+ const {
|
|
|
+ getNodes,
|
|
|
+ } = store.getState()
|
|
|
+
|
|
|
+ const nodes = getNodes()
|
|
|
+ const nodesToCopy = nodes.filter(node => node.data.selected)
|
|
|
+
|
|
|
+ setClipboardElements(nodesToCopy)
|
|
|
+
|
|
|
+ return nodesToCopy
|
|
|
+ }, [getNodesReadOnly, store, workflowStore])
|
|
|
+
|
|
|
+ const handleNodePaste = useCallback((): undefined | Node[] => {
|
|
|
+ if (getNodesReadOnly())
|
|
|
+ return
|
|
|
+
|
|
|
+ const {
|
|
|
+ clipboardElements,
|
|
|
+ } = workflowStore.getState()
|
|
|
+
|
|
|
+ const {
|
|
|
+ getNodes,
|
|
|
+ setNodes,
|
|
|
+ } = store.getState()
|
|
|
+
|
|
|
+ const nodesToPaste: Node[] = []
|
|
|
+ const nodes = getNodes()
|
|
|
+
|
|
|
+ for (const nodeToPaste of clipboardElements) {
|
|
|
+ const nodeType = nodeToPaste.data.type
|
|
|
+ const nodesWithSameType = nodes.filter(node => node.data.type === nodeType)
|
|
|
+
|
|
|
+ const newNode = generateNewNode({
|
|
|
+ data: {
|
|
|
+ ...NODES_INITIAL_DATA[nodeType],
|
|
|
+ ...nodeToPaste.data,
|
|
|
+ _connectedSourceHandleIds: [],
|
|
|
+ _connectedTargetHandleIds: [],
|
|
|
+ title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${nodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${nodeType}`),
|
|
|
+ selected: true,
|
|
|
+ },
|
|
|
+ position: {
|
|
|
+ x: nodeToPaste.position.x + 10,
|
|
|
+ y: nodeToPaste.position.y + 10,
|
|
|
+ },
|
|
|
+ })
|
|
|
+ nodesToPaste.push(newNode)
|
|
|
+ }
|
|
|
+
|
|
|
+ setNodes([...nodes.map((n: Node) => ({ ...n, selected: false, data: { ...n.data, selected: false } })), ...nodesToPaste])
|
|
|
+
|
|
|
+ handleSyncWorkflowDraft()
|
|
|
+
|
|
|
+ return nodesToPaste
|
|
|
+ }, [getNodesReadOnly, handleSyncWorkflowDraft, store, t, workflowStore])
|
|
|
+
|
|
|
+ const handleNodeDuplicateSelected = useCallback(() => {
|
|
|
+ if (getNodesReadOnly())
|
|
|
+ return
|
|
|
+
|
|
|
+ handleNodeCopySelected()
|
|
|
+ handleNodePaste()
|
|
|
+ }, [getNodesReadOnly, handleNodeCopySelected, handleNodePaste])
|
|
|
+
|
|
|
+ const handleNodeCut = useCallback(() => {
|
|
|
+ if (getNodesReadOnly())
|
|
|
+ return
|
|
|
+
|
|
|
+ const nodesToCut = handleNodeCopySelected()
|
|
|
+ if (!nodesToCut)
|
|
|
+ return
|
|
|
+
|
|
|
+ for (const node of nodesToCut)
|
|
|
+ handleNodeDelete(node.id)
|
|
|
+ }, [getNodesReadOnly, handleNodeCopySelected, handleNodeDelete])
|
|
|
+
|
|
|
+ const handleNodeDeleteSelected = useCallback(() => {
|
|
|
+ if (getNodesReadOnly())
|
|
|
+ return
|
|
|
+
|
|
|
+ const {
|
|
|
+ getNodes,
|
|
|
+ } = store.getState()
|
|
|
+
|
|
|
+ const nodes = getNodes()
|
|
|
+ const nodesToDelete = nodes.filter(node => node.data.selected)
|
|
|
+
|
|
|
+ if (!nodesToDelete)
|
|
|
+ return
|
|
|
+
|
|
|
+ for (const node of nodesToDelete)
|
|
|
+ handleNodeDelete(node.id)
|
|
|
+ }, [getNodesReadOnly, handleNodeDelete, store])
|
|
|
+
|
|
|
return {
|
|
|
handleNodeDragStart,
|
|
|
handleNodeDrag,
|
|
@@ -729,5 +831,10 @@ export const useNodesInteractions = () => {
|
|
|
handleNodeDelete,
|
|
|
handleNodeChange,
|
|
|
handleNodeAdd,
|
|
|
+ handleNodeDuplicateSelected,
|
|
|
+ handleNodeCopySelected,
|
|
|
+ handleNodeCut,
|
|
|
+ handleNodeDeleteSelected,
|
|
|
+ handleNodePaste,
|
|
|
}
|
|
|
}
|