| import { useCallback } from 'react' |
| import produce from 'immer' |
| import { useTranslation } from 'react-i18next' |
| import { useStoreApi } from 'reactflow' |
| import type { |
| BlockEnum, |
| Node, |
| } from '../../types' |
| import { generateNewNode } from '../../utils' |
| import { |
| ITERATION_PADDING, |
| NODES_INITIAL_DATA, |
| } from '../../constants' |
| import { CUSTOM_ITERATION_START_NODE } from '../iteration-start/constants' |
|
|
| export const useNodeIterationInteractions = () => { |
| const { t } = useTranslation() |
| const store = useStoreApi() |
|
|
| const handleNodeIterationRerender = useCallback((nodeId: string) => { |
| const { |
| getNodes, |
| setNodes, |
| } = store.getState() |
|
|
| const nodes = getNodes() |
| const currentNode = nodes.find(n => n.id === nodeId)! |
| const childrenNodes = nodes.filter(n => n.parentId === nodeId) |
| let rightNode: Node |
| let bottomNode: Node |
|
|
| childrenNodes.forEach((n) => { |
| if (rightNode) { |
| if (n.position.x + n.width! > rightNode.position.x + rightNode.width!) |
| rightNode = n |
| } |
| else { |
| rightNode = n |
| } |
| if (bottomNode) { |
| if (n.position.y + n.height! > bottomNode.position.y + bottomNode.height!) |
| bottomNode = n |
| } |
| else { |
| bottomNode = n |
| } |
| }) |
|
|
| const widthShouldExtend = rightNode! && currentNode.width! < rightNode.position.x + rightNode.width! |
| const heightShouldExtend = bottomNode! && currentNode.height! < bottomNode.position.y + bottomNode.height! |
|
|
| if (widthShouldExtend || heightShouldExtend) { |
| const newNodes = produce(nodes, (draft) => { |
| draft.forEach((n) => { |
| if (n.id === nodeId) { |
| if (widthShouldExtend) { |
| n.data.width = rightNode.position.x + rightNode.width! + ITERATION_PADDING.right |
| n.width = rightNode.position.x + rightNode.width! + ITERATION_PADDING.right |
| } |
| if (heightShouldExtend) { |
| n.data.height = bottomNode.position.y + bottomNode.height! + ITERATION_PADDING.bottom |
| n.height = bottomNode.position.y + bottomNode.height! + ITERATION_PADDING.bottom |
| } |
| } |
| }) |
| }) |
|
|
| setNodes(newNodes) |
| } |
| }, [store]) |
|
|
| const handleNodeIterationChildDrag = useCallback((node: Node) => { |
| const { getNodes } = store.getState() |
| const nodes = getNodes() |
|
|
| const restrictPosition: { x?: number; y?: number } = { x: undefined, y: undefined } |
|
|
| if (node.data.isInIteration) { |
| const parentNode = nodes.find(n => n.id === node.parentId) |
|
|
| if (parentNode) { |
| if (node.position.y < ITERATION_PADDING.top) |
| restrictPosition.y = ITERATION_PADDING.top |
| if (node.position.x < ITERATION_PADDING.left) |
| restrictPosition.x = ITERATION_PADDING.left |
| if (node.position.x + node.width! > parentNode!.width! - ITERATION_PADDING.right) |
| restrictPosition.x = parentNode!.width! - ITERATION_PADDING.right - node.width! |
| if (node.position.y + node.height! > parentNode!.height! - ITERATION_PADDING.bottom) |
| restrictPosition.y = parentNode!.height! - ITERATION_PADDING.bottom - node.height! |
| } |
| } |
|
|
| return { |
| restrictPosition, |
| } |
| }, [store]) |
|
|
| const handleNodeIterationChildSizeChange = useCallback((nodeId: string) => { |
| const { getNodes } = store.getState() |
| const nodes = getNodes() |
| const currentNode = nodes.find(n => n.id === nodeId)! |
| const parentId = currentNode.parentId |
|
|
| if (parentId) |
| handleNodeIterationRerender(parentId) |
| }, [store, handleNodeIterationRerender]) |
|
|
| const handleNodeIterationChildrenCopy = useCallback((nodeId: string, newNodeId: string) => { |
| const { getNodes } = store.getState() |
| const nodes = getNodes() |
| const childrenNodes = nodes.filter(n => n.parentId === nodeId && n.type !== CUSTOM_ITERATION_START_NODE) |
|
|
| return childrenNodes.map((child, index) => { |
| const childNodeType = child.data.type as BlockEnum |
| const nodesWithSameType = nodes.filter(node => node.data.type === childNodeType) |
| const { newNode } = generateNewNode({ |
| data: { |
| ...NODES_INITIAL_DATA[childNodeType], |
| ...child.data, |
| selected: false, |
| _isBundled: false, |
| _connectedSourceHandleIds: [], |
| _connectedTargetHandleIds: [], |
| title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${childNodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${childNodeType}`), |
| iteration_id: newNodeId, |
| }, |
| position: child.position, |
| positionAbsolute: child.positionAbsolute, |
| parentId: newNodeId, |
| extent: child.extent, |
| zIndex: child.zIndex, |
| }) |
| newNode.id = `${newNodeId}${newNode.id + index}` |
| return newNode |
| }) |
| }, [store, t]) |
|
|
| return { |
| handleNodeIterationRerender, |
| handleNodeIterationChildDrag, |
| handleNodeIterationChildSizeChange, |
| handleNodeIterationChildrenCopy, |
| } |
| } |
|
|