Co-authored-by: Yeuoly <admin@srmxy.cn>tags/0.6.10
| @@ -7,7 +7,7 @@ from pydantic import BaseModel | |||
| from core.workflow.entities.base_node_data_entities import BaseNodeData | |||
| class AdvancedSetting(BaseModel): | |||
| class AdvancedSettings(BaseModel): | |||
| """ | |||
| Advanced setting. | |||
| """ | |||
| @@ -30,4 +30,4 @@ class VariableAssignerNodeData(BaseNodeData): | |||
| type: str = 'variable-assigner' | |||
| output_type: str | |||
| variables: list[list[str]] | |||
| advanced_setting: Optional[AdvancedSetting] | |||
| advanced_settings: Optional[AdvancedSettings] | |||
| @@ -18,7 +18,7 @@ class VariableAggregatorNode(BaseNode): | |||
| outputs = {} | |||
| inputs = {} | |||
| if not node_data.advanced_setting or node_data.advanced_setting.group_enabled: | |||
| if not node_data.advanced_settings or not node_data.advanced_settings.group_enabled: | |||
| for variable in node_data.variables: | |||
| value = variable_pool.get_variable_value(variable) | |||
| @@ -32,12 +32,14 @@ class VariableAggregatorNode(BaseNode): | |||
| } | |||
| break | |||
| else: | |||
| for group in node_data.advanced_setting.groups: | |||
| for group in node_data.advanced_settings.groups: | |||
| for variable in group.variables: | |||
| value = variable_pool.get_variable_value(variable) | |||
| if value is not None: | |||
| outputs[f'{group.group_name}_output'] = value | |||
| outputs[group.group_name] = { | |||
| 'output': value | |||
| } | |||
| inputs['.'.join(variable[1:])] = value | |||
| break | |||
| @@ -164,6 +164,7 @@ export const useNodesInteractions = () => { | |||
| if (sameLevel) { | |||
| setEnteringNodePayload({ | |||
| nodeId: node.id, | |||
| nodeData: node.data as VariableAssignerNodeType, | |||
| }) | |||
| const fromType = connectingNodePayload.handleType | |||
| @@ -360,6 +361,11 @@ export const useNodesInteractions = () => { | |||
| const { getNodes } = store.getState() | |||
| const node = getNodes().find(n => n.id === nodeId)! | |||
| if (node.data.type === BlockEnum.VariableAggregator || node.data.type === BlockEnum.VariableAssigner) { | |||
| if (handleType === 'target') | |||
| return | |||
| } | |||
| if (!node.data.isIterationStart) { | |||
| setConnectingNodePayload({ | |||
| nodeId, | |||
| @@ -395,7 +401,6 @@ export const useNodesInteractions = () => { | |||
| const fromHandleType = connectingNodePayload.handleType | |||
| const fromHandleId = connectingNodePayload.handleId | |||
| const fromNode = nodes.find(n => n.id === connectingNodePayload.nodeId)! | |||
| const fromNodeParent = nodes.find(n => n.id === fromNode.parentId) | |||
| const toNode = nodes.find(n => n.id === enteringNodePayload.nodeId)! | |||
| const toParentNode = nodes.find(n => n.id === toNode.parentId) | |||
| @@ -406,39 +411,15 @@ export const useNodesInteractions = () => { | |||
| if (fromHandleType === 'source' && (toNode.data.type === BlockEnum.VariableAssigner || toNode.data.type === BlockEnum.VariableAggregator)) { | |||
| const groupEnabled = toNode.data.advanced_settings?.group_enabled | |||
| if ( | |||
| (groupEnabled && hoveringAssignVariableGroupId) | |||
| || !groupEnabled | |||
| ) { | |||
| const newNodes = produce(nodes, (draft) => { | |||
| draft.forEach((node) => { | |||
| if (node.id === toNode.id) { | |||
| node.data._showAddVariablePopup = true | |||
| node.data._holdAddVariablePopup = true | |||
| } | |||
| }) | |||
| }) | |||
| setNodes(newNodes) | |||
| setShowAssignVariablePopup({ | |||
| nodeId: fromNode.id, | |||
| nodeData: fromNode.data, | |||
| variableAssignerNodeId: toNode.id, | |||
| variableAssignerNodeData: toNode.data, | |||
| variableAssignerNodeHandleId: hoveringAssignVariableGroupId || 'target', | |||
| parentNode: toParentNode, | |||
| x: x - toNode.positionAbsolute!.x, | |||
| y: y - toNode.positionAbsolute!.y, | |||
| }) | |||
| handleNodeConnect({ | |||
| source: fromNode.id, | |||
| sourceHandle: fromHandleId, | |||
| target: toNode.id, | |||
| targetHandle: hoveringAssignVariableGroupId || 'target', | |||
| }) | |||
| const firstGroupId = toNode.data.advanced_settings?.groups[0].groupId | |||
| let handleId = 'target' | |||
| if (groupEnabled) { | |||
| if (hoveringAssignVariableGroupId) | |||
| handleId = hoveringAssignVariableGroupId | |||
| else | |||
| handleId = firstGroupId | |||
| } | |||
| } | |||
| if (fromHandleType === 'target' && (fromNode.data.type === BlockEnum.VariableAssigner || fromNode.data.type === BlockEnum.VariableAggregator) && toNode.data.type !== BlockEnum.IfElse && toNode.data.type !== BlockEnum.QuestionClassifier) { | |||
| const newNodes = produce(nodes, (draft) => { | |||
| draft.forEach((node) => { | |||
| if (node.id === toNode.id) { | |||
| @@ -449,20 +430,20 @@ export const useNodesInteractions = () => { | |||
| }) | |||
| setNodes(newNodes) | |||
| setShowAssignVariablePopup({ | |||
| nodeId: toNode.id, | |||
| nodeData: toNode.data, | |||
| variableAssignerNodeId: fromNode.id, | |||
| variableAssignerNodeData: fromNode.data, | |||
| variableAssignerNodeHandleId: fromHandleId || 'target', | |||
| parentNode: fromNodeParent, | |||
| nodeId: fromNode.id, | |||
| nodeData: fromNode.data, | |||
| variableAssignerNodeId: toNode.id, | |||
| variableAssignerNodeData: toNode.data, | |||
| variableAssignerNodeHandleId: handleId, | |||
| parentNode: toParentNode, | |||
| x: x - toNode.positionAbsolute!.x, | |||
| y: y - toNode.positionAbsolute!.y, | |||
| }) | |||
| handleNodeConnect({ | |||
| source: toNode.id, | |||
| sourceHandle: 'source', | |||
| target: fromNode.id, | |||
| targetHandle: fromHandleId, | |||
| source: fromNode.id, | |||
| sourceHandle: fromHandleId, | |||
| target: toNode.id, | |||
| targetHandle: 'target', | |||
| }) | |||
| } | |||
| } | |||
| @@ -1111,7 +1092,7 @@ export const useNodesInteractions = () => { | |||
| setNodes([...nodes, ...nodesToPaste]) | |||
| handleSyncWorkflowDraft() | |||
| } | |||
| }, [t, getNodesReadOnly, store, workflowStore, handleSyncWorkflowDraft, reactflow, handleNodeIterationChildrenCopy]) | |||
| }, [getNodesReadOnly, store, workflowStore, handleSyncWorkflowDraft, reactflow, handleNodeIterationChildrenCopy]) | |||
| const handleNodesDuplicate = useCallback(() => { | |||
| if (getNodesReadOnly()) | |||
| @@ -207,7 +207,7 @@ const Workflow: FC<WorkflowProps> = memo(({ | |||
| }) | |||
| useKeyPress('delete', handleNodesDelete) | |||
| useKeyPress('delete', handleEdgeDelete) | |||
| useKeyPress(['delete', 'backspace'], handleEdgeDelete) | |||
| useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.c`, handleNodesCopy, { exactMatch: true, useCapture: true }) | |||
| useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.v`, handleNodesPaste, { exactMatch: true, useCapture: true }) | |||
| useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.d`, handleNodesDuplicate, { exactMatch: true, useCapture: true }) | |||
| @@ -43,7 +43,9 @@ const AddVariablePopupWithPosition = ({ | |||
| if (!showAssignVariablePopup) | |||
| return '' | |||
| if (showAssignVariablePopup.variableAssignerNodeHandleId === 'target') | |||
| const groupEnabled = showAssignVariablePopup.variableAssignerNodeData.advanced_settings?.group_enabled | |||
| if (!groupEnabled) | |||
| return showAssignVariablePopup.variableAssignerNodeData.output_type | |||
| const group = showAssignVariablePopup.variableAssignerNodeData.advanced_settings?.groups.find(group => group.groupId === showAssignVariablePopup.variableAssignerNodeHandleId) | |||
| @@ -113,13 +113,11 @@ export const NodeSourceHandle = memo(({ | |||
| nodeSelectorClassName, | |||
| }: NodeHandleProps) => { | |||
| const notInitialWorkflow = useStore(s => s.notInitialWorkflow) | |||
| const connectingNodePayload = useStore(s => s.connectingNodePayload) | |||
| const [open, setOpen] = useState(false) | |||
| const { handleNodeAdd } = useNodesInteractions() | |||
| const { getNodesReadOnly } = useNodesReadOnly() | |||
| const { availableNextBlocks } = useAvailableBlocks(data.type, data.isInIteration) | |||
| const isUnConnectable = !availableNextBlocks.length || ((connectingNodePayload?.nodeType === BlockEnum.VariableAssigner || connectingNodePayload?.nodeType === BlockEnum.VariableAggregator) && connectingNodePayload?.handleType === 'target') | |||
| const isConnectable = !isUnConnectable | |||
| const isConnectable = !!availableNextBlocks.length | |||
| const connected = data._connectedSourceHandleIds?.includes(handleId) | |||
| const handleOpenChange = useCallback((v: boolean) => { | |||
| @@ -117,7 +117,7 @@ const BaseNode: FC<BaseNodeProps> = ({ | |||
| ) | |||
| } | |||
| { | |||
| data.type !== BlockEnum.VariableAssigner && data.type !== BlockEnum.VariableAggregator && !data._isCandidate && ( | |||
| !data._isCandidate && ( | |||
| <NodeTargetHandle | |||
| id={id} | |||
| data={data} | |||
| @@ -1,6 +1,7 @@ | |||
| import { | |||
| memo, | |||
| useCallback, | |||
| useState, | |||
| } from 'react' | |||
| import cn from 'classnames' | |||
| import { useVariableAssigner } from '../../hooks' | |||
| @@ -19,21 +20,18 @@ import type { | |||
| } from '@/app/components/workflow/types' | |||
| export type AddVariableProps = { | |||
| open: boolean | |||
| onOpenChange: (open: boolean) => void | |||
| variableAssignerNodeId: string | |||
| variableAssignerNodeData: VariableAssignerNodeType | |||
| availableVars: NodeOutPutVar[] | |||
| handleId?: string | |||
| } | |||
| const AddVariable = ({ | |||
| open, | |||
| onOpenChange, | |||
| availableVars, | |||
| variableAssignerNodeId, | |||
| variableAssignerNodeData, | |||
| handleId, | |||
| }: AddVariableProps) => { | |||
| const [open, setOpen] = useState(false) | |||
| const { handleAssignVariableValueChange } = useVariableAssigner() | |||
| const handleSelectVariable = useCallback((v: ValueSelector, varDetail: Var) => { | |||
| @@ -43,34 +41,38 @@ const AddVariable = ({ | |||
| varDetail, | |||
| handleId, | |||
| ) | |||
| onOpenChange(false) | |||
| }, [handleAssignVariableValueChange, variableAssignerNodeId, handleId, onOpenChange]) | |||
| setOpen(false) | |||
| }, [handleAssignVariableValueChange, variableAssignerNodeId, handleId, setOpen]) | |||
| return ( | |||
| <div className={cn( | |||
| 'hidden group-hover:flex absolute top-0 left-0 z-10 pointer-events-none', | |||
| open && '!flex', | |||
| variableAssignerNodeData.selected && '!flex', | |||
| )}> | |||
| <PortalToFollowElem | |||
| placement={'left-start'} | |||
| offset={{ | |||
| mainAxis: 4, | |||
| crossAxis: -60, | |||
| }} | |||
| placement={'right'} | |||
| offset={4} | |||
| open={open} | |||
| onOpenChange={onOpenChange} | |||
| onOpenChange={setOpen} | |||
| > | |||
| <PortalToFollowElemTrigger | |||
| onClick={() => onOpenChange(!open)} | |||
| onClick={() => setOpen(!open)} | |||
| > | |||
| <div | |||
| className={cn( | |||
| 'flex items-center justify-center', | |||
| 'w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10', | |||
| 'group/addvariable flex items-center justify-center', | |||
| 'w-4 h-4 cursor-pointer', | |||
| 'hover:rounded-full hover:bg-primary-600', | |||
| open && '!rounded-full !bg-primary-600', | |||
| )} | |||
| > | |||
| <Plus02 className='w-2.5 h-2.5 text-white' /> | |||
| <Plus02 | |||
| className={cn( | |||
| 'w-2.5 h-2.5 text-gray-500', | |||
| 'group-hover/addvariable:text-white', | |||
| open && '!text-white', | |||
| )} | |||
| /> | |||
| </div> | |||
| </PortalToFollowElemTrigger> | |||
| <PortalToFollowElemContent className='z-[1000]'> | |||
| @@ -18,7 +18,7 @@ import { | |||
| useVariableAssigner, | |||
| } from '../hooks' | |||
| import { filterVar } from '../utils' | |||
| import NodeHandle from './node-handle' | |||
| import AddVariable from './add-variable' | |||
| import NodeVariableItem from './node-variable-item' | |||
| import { isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils' | |||
| @@ -47,40 +47,75 @@ const NodeGroupItem = ({ | |||
| handleGroupItemMouseLeave, | |||
| } = useVariableAssigner() | |||
| const getAvailableVars = useGetAvailableVars() | |||
| const groupEnabled = item.groupEnabled | |||
| const outputType = useMemo(() => { | |||
| if (item.targetHandleId === 'target') | |||
| if (!groupEnabled) | |||
| return item.variableAssignerNodeData.output_type | |||
| const group = item.variableAssignerNodeData.advanced_settings?.groups.find(group => group.groupId === item.targetHandleId) | |||
| return group?.output_type || '' | |||
| }, [item.variableAssignerNodeData, item.targetHandleId]) | |||
| }, [item.variableAssignerNodeData, item.targetHandleId, groupEnabled]) | |||
| const availableVars = getAvailableVars(item.variableAssignerNodeId, item.targetHandleId, filterVar(outputType as VarType)) | |||
| const showSelectionBorder = enteringNodePayload?.nodeId === item.variableAssignerNodeId && item.groupEnabled && hoveringAssignVariableGroupId === item.targetHandleId | |||
| const connected = item.variableAssignerNodeData._connectedTargetHandleIds?.includes(item.targetHandleId) | |||
| const showSelectionBorder = useMemo(() => { | |||
| if (groupEnabled && enteringNodePayload?.nodeId === item.variableAssignerNodeId) { | |||
| if (hoveringAssignVariableGroupId) | |||
| return hoveringAssignVariableGroupId !== item.targetHandleId | |||
| else | |||
| return enteringNodePayload?.nodeData.advanced_settings?.groups[0].groupId !== item.targetHandleId | |||
| } | |||
| return false | |||
| }, [enteringNodePayload, groupEnabled, hoveringAssignVariableGroupId, item.targetHandleId, item.variableAssignerNodeId]) | |||
| const showSelectedBorder = useMemo(() => { | |||
| if (groupEnabled && enteringNodePayload?.nodeId === item.variableAssignerNodeId) { | |||
| if (hoveringAssignVariableGroupId) | |||
| return hoveringAssignVariableGroupId === item.targetHandleId | |||
| else | |||
| return enteringNodePayload?.nodeData.advanced_settings?.groups[0].groupId === item.targetHandleId | |||
| } | |||
| return false | |||
| }, [enteringNodePayload, groupEnabled, hoveringAssignVariableGroupId, item.targetHandleId, item.variableAssignerNodeId]) | |||
| return ( | |||
| <div | |||
| className={cn( | |||
| 'relative pt-1 px-1.5 pb-1.5 rounded-lg border border-transparent', | |||
| showSelectionBorder && '!border-primary-600', | |||
| 'relative pt-1 px-1.5 pb-1.5 rounded-lg border-[1.5px] border-transparent', | |||
| showSelectionBorder && '!border-gray-300 !border-dashed bg-black/[0.02]', | |||
| showSelectedBorder && '!border-primary-600 !bg-primary-50', | |||
| )} | |||
| onMouseEnter={() => handleGroupItemMouseEnter(item.targetHandleId)} | |||
| onMouseEnter={() => groupEnabled && handleGroupItemMouseEnter(item.targetHandleId)} | |||
| onMouseLeave={handleGroupItemMouseLeave} | |||
| > | |||
| <div className='flex items-center justify-between h-4 text-[10px] font-medium text-gray-500'> | |||
| <NodeHandle | |||
| connected={connected} | |||
| variableAssignerNodeId={item.variableAssignerNodeId} | |||
| variableAssignerNodeData={item.variableAssignerNodeData} | |||
| handleId={item.targetHandleId} | |||
| availableVars={availableVars} | |||
| /> | |||
| <span className='grow uppercase truncate' title={item.title}>{item.title}</span> | |||
| <span className='shrink-0 ml-2'>{item.type}</span> | |||
| <span | |||
| className={cn( | |||
| 'grow uppercase truncate', | |||
| showSelectedBorder && 'text-primary-600', | |||
| )} | |||
| title={item.title} | |||
| > | |||
| {item.title} | |||
| </span> | |||
| <div className='flex items-center'> | |||
| <span className='shrink-0 ml-2'>{item.type}</span> | |||
| <div className='ml-2 mr-1 w-[1px] h-2.5 bg-gray-200'></div> | |||
| <AddVariable | |||
| availableVars={availableVars} | |||
| variableAssignerNodeId={item.variableAssignerNodeId} | |||
| variableAssignerNodeData={item.variableAssignerNodeData} | |||
| handleId={item.targetHandleId} | |||
| /> | |||
| </div> | |||
| </div> | |||
| { | |||
| !item.variables.length && ( | |||
| <div className='relative flex items-center px-1 h-[22px] justify-between bg-gray-100 rounded-md space-x-1 text-[10px] font-normal text-gray-400 uppercase'> | |||
| <div | |||
| className={cn( | |||
| 'relative flex items-center px-1 h-[22px] justify-between bg-gray-100 rounded-md space-x-1 text-[10px] font-normal text-gray-400 uppercase', | |||
| (showSelectedBorder || showSelectionBorder) && '!bg-black/[0.02]', | |||
| )} | |||
| > | |||
| {t(`${i18nPrefix}.varNotSet`)} | |||
| </div> | |||
| ) | |||
| @@ -96,6 +131,7 @@ const NodeGroupItem = ({ | |||
| key={index} | |||
| node={node as Node} | |||
| varName={varName} | |||
| showBorder={showSelectedBorder || showSelectionBorder} | |||
| /> | |||
| ) | |||
| }) | |||
| @@ -1,69 +0,0 @@ | |||
| import type { MouseEvent } from 'react' | |||
| import { | |||
| memo, | |||
| useCallback, | |||
| useState, | |||
| } from 'react' | |||
| import cn from 'classnames' | |||
| import { | |||
| Handle, | |||
| Position, | |||
| } from 'reactflow' | |||
| import type { VariableAssignerNodeType } from '../types' | |||
| import AddVariable from './add-variable' | |||
| import type { NodeOutPutVar } from '@/app/components/workflow/types' | |||
| import { useStore } from '@/app/components/workflow/store' | |||
| type NodeHandleProps = { | |||
| handleId?: string | |||
| connected?: boolean | |||
| variableAssignerNodeId: string | |||
| availableVars: NodeOutPutVar[] | |||
| variableAssignerNodeData: VariableAssignerNodeType | |||
| } | |||
| const NodeHandle = ({ | |||
| connected, | |||
| variableAssignerNodeId, | |||
| handleId = 'target', | |||
| availableVars, | |||
| variableAssignerNodeData, | |||
| }: NodeHandleProps) => { | |||
| const [open, setOpen] = useState(false) | |||
| const connectingNodePayload = useStore(s => s.connectingNodePayload) | |||
| const isUnConnectable = connectingNodePayload?.handleType === 'source' | |||
| const handleOpenChange = useCallback((v: boolean) => { | |||
| setOpen(v) | |||
| }, []) | |||
| const handleHandleClick = useCallback((e: MouseEvent) => { | |||
| e.stopPropagation() | |||
| setOpen(v => !v) | |||
| }, []) | |||
| return ( | |||
| <Handle | |||
| id={handleId} | |||
| type='target' | |||
| onClick={handleHandleClick} | |||
| position={Position.Left} | |||
| isConnectable={!isUnConnectable} | |||
| className={cn( | |||
| '!-left-[13px] !top-1 !w-4 !h-4 !bg-transparent !rounded-none !outline-none !border-none z-[1] !transform-none', | |||
| 'after:absolute after:w-0.5 after:h-2 after:left-[5px] after:top-1 after:bg-primary-500 pointer-events-none', | |||
| !connected && 'after:opacity-0', | |||
| )} | |||
| > | |||
| <AddVariable | |||
| open={open} | |||
| onOpenChange={handleOpenChange} | |||
| variableAssignerNodeId={variableAssignerNodeId} | |||
| variableAssignerNodeData={variableAssignerNodeData} | |||
| handleId={handleId} | |||
| availableVars={availableVars} | |||
| /> | |||
| </Handle> | |||
| ) | |||
| } | |||
| export default memo(NodeHandle) | |||
| @@ -1,4 +1,5 @@ | |||
| import { memo } from 'react' | |||
| import cn from 'classnames' | |||
| import { VarBlockIcon } from '@/app/components/workflow/block-icon' | |||
| import { Line3 } from '@/app/components/base/icons/src/public/common' | |||
| import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development' | |||
| @@ -8,13 +9,18 @@ import { BlockEnum } from '@/app/components/workflow/types' | |||
| type NodeVariableItemProps = { | |||
| node: Node | |||
| varName: string | |||
| showBorder?: boolean | |||
| } | |||
| const NodeVariableItem = ({ | |||
| node, | |||
| varName, | |||
| showBorder, | |||
| }: NodeVariableItemProps) => { | |||
| return ( | |||
| <div className='relative flex items-center mt-0.5 h-6 bg-gray-100 rounded-md px-1 text-xs font-normal text-gray-700' > | |||
| <div className={cn( | |||
| 'relative flex items-center mt-0.5 h-6 bg-gray-100 rounded-md px-1 text-xs font-normal text-gray-700', | |||
| showBorder && '!bg-black/[0.02]', | |||
| )}> | |||
| <div className='flex items-center'> | |||
| <div className='p-[1px]'> | |||
| <VarBlockIcon | |||
| @@ -1,6 +1,5 @@ | |||
| import { useCallback } from 'react' | |||
| import { | |||
| useEdges, | |||
| useNodes, | |||
| useStoreApi, | |||
| } from 'reactflow' | |||
| @@ -12,9 +11,7 @@ import { | |||
| useNodeDataUpdate, | |||
| useWorkflow, | |||
| } from '../../hooks' | |||
| import { getNodesConnectedSourceOrTargetHandleIdsMap } from '../../utils' | |||
| import type { | |||
| Edge, | |||
| Node, | |||
| ValueSelector, | |||
| Var, | |||
| @@ -99,82 +96,6 @@ export const useVariableAssigner = () => { | |||
| handleAssignVariableValueChange(variableAssignerNodeId, value, varDetail, variableAssignerNodeHandleId) | |||
| }, [store, workflowStore, handleAssignVariableValueChange]) | |||
| const handleRemoveEdges = useCallback((nodeId: string, enabled: boolean) => { | |||
| const { | |||
| getNodes, | |||
| setNodes, | |||
| edges, | |||
| setEdges, | |||
| } = store.getState() | |||
| const nodes = getNodes() | |||
| const needDeleteEdges = edges.filter(edge => edge.target === nodeId) | |||
| if (!needDeleteEdges.length) | |||
| return | |||
| const currentNode = nodes.find(node => node.id === nodeId)! | |||
| const groups = currentNode.data.advanced_settings?.groups || [] | |||
| let shouldKeepEdges: Edge[] = [] | |||
| if (enabled) { | |||
| shouldKeepEdges = edges.filter((edge) => { | |||
| return edge.target === nodeId && edge.targetHandle === 'target' | |||
| }).map((edge) => { | |||
| return { | |||
| ...edge, | |||
| targetHandle: groups[0].groupId, | |||
| } | |||
| }) | |||
| } | |||
| else { | |||
| shouldKeepEdges = edges.filter((edge) => { | |||
| return edge.target === nodeId && edge.targetHandle === groups[0].groupId | |||
| }).map((edge) => { | |||
| return { | |||
| ...edge, | |||
| targetHandle: 'target', | |||
| } | |||
| }) | |||
| } | |||
| const nodesConnectedSourceOrTargetHandleIdsMap = getNodesConnectedSourceOrTargetHandleIdsMap( | |||
| [ | |||
| ...needDeleteEdges.map((needDeleteEdge) => { | |||
| return { | |||
| type: 'remove', | |||
| edge: needDeleteEdge, | |||
| } | |||
| }), | |||
| ...shouldKeepEdges.map((shouldKeepEdge) => { | |||
| return { | |||
| type: 'add', | |||
| edge: shouldKeepEdge, | |||
| } | |||
| }), | |||
| ], | |||
| nodes, | |||
| ) | |||
| const newNodes = produce(nodes, (draft) => { | |||
| draft.forEach((node) => { | |||
| if (nodesConnectedSourceOrTargetHandleIdsMap[node.id]) { | |||
| node.data = { | |||
| ...node.data, | |||
| ...nodesConnectedSourceOrTargetHandleIdsMap[node.id], | |||
| } | |||
| } | |||
| }) | |||
| }) | |||
| setNodes(newNodes) | |||
| const newEdges = produce(edges, (draft) => { | |||
| draft = draft.filter(edge => edge.target !== nodeId) | |||
| draft.push(...shouldKeepEdges) | |||
| return draft | |||
| }) | |||
| setEdges(newEdges) | |||
| }, [store]) | |||
| const handleGroupItemMouseEnter = useCallback((groupId: string) => { | |||
| const { | |||
| setHoveringAssignVariableGroupId, | |||
| @@ -195,7 +116,6 @@ export const useVariableAssigner = () => { | |||
| return { | |||
| handleAddVariableInAddVariablePopupWithPosition, | |||
| handleRemoveEdges, | |||
| handleGroupItemMouseEnter, | |||
| handleGroupItemMouseLeave, | |||
| handleAssignVariableValueChange, | |||
| @@ -205,8 +125,7 @@ export const useVariableAssigner = () => { | |||
| export const useGetAvailableVars = () => { | |||
| const { t } = useTranslation() | |||
| const nodes: Node[] = useNodes() | |||
| const edges: Edge[] = useEdges() | |||
| const { getBeforeNodesInSameBranch } = useWorkflow() | |||
| const { getBeforeNodesInSameBranchIncludeParent } = useWorkflow() | |||
| const isChatMode = useIsChatMode() | |||
| const getAvailableVars = useCallback((nodeId: string, handleId: string, filterVar: (v: Var) => boolean) => { | |||
| const availableNodes: Node[] = [] | |||
| @@ -214,21 +133,10 @@ export const useGetAvailableVars = () => { | |||
| if (!currentNode) | |||
| return [] | |||
| const parentNode = nodes.find(node => node.id === currentNode.parentId) | |||
| const connectedEdges = edges.filter(edge => edge.target === nodeId && edge.targetHandle === handleId) | |||
| if (parentNode && !connectedEdges.length) { | |||
| const beforeNodes = getBeforeNodesInSameBranch(parentNode.id) | |||
| availableNodes.push(...beforeNodes) | |||
| } | |||
| else { | |||
| connectedEdges.forEach((connectedEdge) => { | |||
| const beforeNodes = getBeforeNodesInSameBranch(connectedEdge.source) | |||
| const connectedNode = nodes.find(node => node.id === connectedEdge.source)! | |||
| availableNodes.push(connectedNode, ...beforeNodes) | |||
| }) | |||
| } | |||
| const beforeNodes = getBeforeNodesInSameBranchIncludeParent(nodeId) | |||
| availableNodes.push(...beforeNodes) | |||
| const parentNode = nodes.find(node => node.id === currentNode.parentId) | |||
| return toNodeAvailableVars({ | |||
| parentNode, | |||
| @@ -237,7 +145,7 @@ export const useGetAvailableVars = () => { | |||
| isChatMode, | |||
| filterVar, | |||
| }) | |||
| }, [nodes, edges, t, isChatMode, getBeforeNodesInSameBranch]) | |||
| }, [nodes, t, isChatMode, getBeforeNodesInSameBranchIncludeParent]) | |||
| return getAvailableVars | |||
| } | |||
| @@ -43,7 +43,7 @@ const Node: FC<NodeProps<VariableAssignerNodeType>> = (props) => { | |||
| }, [t, advanced_settings, data, id]) | |||
| return ( | |||
| <div className='relative mb-1 px-1' ref={ref}> | |||
| <div className='relative mb-1 px-1 space-y-0.5' ref={ref}> | |||
| { | |||
| groups.map((item) => { | |||
| return ( | |||
| @@ -1,16 +1,16 @@ | |||
| import type { FC } from 'react' | |||
| import React from 'react' | |||
| import { useTranslation } from 'react-i18next' | |||
| // import cn from 'classnames' | |||
| // import Field from '../_base/components/field' | |||
| import cn from 'classnames' | |||
| import Field from '../_base/components/field' | |||
| import RemoveEffectVarConfirm from '../_base/components/remove-effect-var-confirm' | |||
| import useConfig from './use-config' | |||
| import type { VariableAssignerNodeType } from './types' | |||
| import VarGroupItem from './components/var-group-item' | |||
| import { type NodePanelProps } from '@/app/components/workflow/types' | |||
| import Split from '@/app/components/workflow/nodes/_base/components/split' | |||
| // import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' | |||
| // import Switch from '@/app/components/base/switch' | |||
| import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' | |||
| import Switch from '@/app/components/base/switch' | |||
| import AddButton from '@/app/components/workflow/nodes/_base/components/add-button' | |||
| const i18nPrefix = 'workflow.nodes.variableAssigner' | |||
| @@ -25,7 +25,7 @@ const Panel: FC<NodePanelProps<VariableAssignerNodeType>> = ({ | |||
| inputs, | |||
| handleListOrTypeChange, | |||
| isEnableGroup, | |||
| // handleGroupEnabledChange, | |||
| handleGroupEnabledChange, | |||
| handleAddGroup, | |||
| handleListOrTypeChangeInGroup, | |||
| handleGroupRemoved, | |||
| @@ -81,8 +81,8 @@ const Panel: FC<NodePanelProps<VariableAssignerNodeType>> = ({ | |||
| /> | |||
| </div>)} | |||
| </div> | |||
| {/* <Split /> */} | |||
| {/* <div className={cn('px-4 pt-4', isEnableGroup ? 'pb-4' : 'pb-2')}> | |||
| <Split /> | |||
| <div className={cn('px-4 pt-4', isEnableGroup ? 'pb-4' : 'pb-2')}> | |||
| <Field | |||
| title={t(`${i18nPrefix}.aggregationGroup`)} | |||
| tooltip={t(`${i18nPrefix}.aggregationGroupTip`)!} | |||
| @@ -95,8 +95,8 @@ const Panel: FC<NodePanelProps<VariableAssignerNodeType>> = ({ | |||
| /> | |||
| } | |||
| /> | |||
| </div> */} | |||
| {/* {isEnableGroup && ( | |||
| </div> | |||
| {isEnableGroup && ( | |||
| <> | |||
| <Split /> | |||
| <div className='px-4 pt-4 pb-2'> | |||
| @@ -116,7 +116,7 @@ const Panel: FC<NodePanelProps<VariableAssignerNodeType>> = ({ | |||
| </OutputVars> | |||
| </div> | |||
| </> | |||
| )} */} | |||
| )} | |||
| <RemoveEffectVarConfirm | |||
| isShow={isShowRemoveVarConfirm} | |||
| onCancel={hideRemoveVarConfirm} | |||
| @@ -5,7 +5,7 @@ import { v4 as uuid4 } from 'uuid' | |||
| import type { ValueSelector, Var } from '../../types' | |||
| import { VarType } from '../../types' | |||
| import type { VarGroupItem, VariableAssignerNodeType } from './types' | |||
| import { useGetAvailableVars, useVariableAssigner } from './hooks' | |||
| import { useGetAvailableVars } from './hooks' | |||
| import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' | |||
| import { | |||
| @@ -19,7 +19,6 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { | |||
| const { inputs, setInputs } = useNodeCrud<VariableAssignerNodeType>(id, payload) | |||
| const isEnableGroup = !!inputs.advanced_settings?.group_enabled | |||
| const { handleRemoveEdges } = useVariableAssigner() | |||
| // Not Enable Group | |||
| const handleListOrTypeChange = useCallback((payload: VarGroupItem) => { | |||
| @@ -114,8 +113,7 @@ const useConfig = (id: string, payload: VariableAssignerNodeType) => { | |||
| draft.advanced_settings.group_enabled = enabled | |||
| }) | |||
| setInputs(newInputs) | |||
| handleRemoveEdges(id, enabled) | |||
| }, [handleOutVarRenameChange, id, inputs, isVarUsedInNodes, setInputs, showRemoveVarConfirm, handleRemoveEdges]) | |||
| }, [handleOutVarRenameChange, id, inputs, isVarUsedInNodes, setInputs, showRemoveVarConfirm]) | |||
| const handleAddGroup = useCallback(() => { | |||
| let maxInGroupName = 1 | |||
| @@ -120,7 +120,10 @@ type Shape = { | |||
| setHoveringAssignVariableGroupId: (hoveringAssignVariableGroupId?: string) => void | |||
| connectingNodePayload?: { nodeId: string; nodeType: string; handleType: string; handleId: string | null } | |||
| setConnectingNodePayload: (startConnectingPayload?: Shape['connectingNodePayload']) => void | |||
| enteringNodePayload?: { nodeId: string } | |||
| enteringNodePayload?: { | |||
| nodeId: string | |||
| nodeData: VariableAssignerNodeType | |||
| } | |||
| setEnteringNodePayload: (enteringNodePayload?: Shape['enteringNodePayload']) => void | |||
| } | |||
| @@ -257,16 +257,20 @@ export const getNodesConnectedSourceOrTargetHandleIdsMap = (changes: ConnectedSo | |||
| } | |||
| if (sourceNode) { | |||
| if (type === 'remove') | |||
| nodesConnectedSourceOrTargetHandleIdsMap[sourceNode.id]._connectedSourceHandleIds = nodesConnectedSourceOrTargetHandleIdsMap[sourceNode.id]._connectedSourceHandleIds.filter((handleId: string) => handleId !== edge.sourceHandle) | |||
| if (type === 'remove') { | |||
| const index = nodesConnectedSourceOrTargetHandleIdsMap[sourceNode.id]._connectedSourceHandleIds.findIndex((handleId: string) => handleId === edge.sourceHandle) | |||
| nodesConnectedSourceOrTargetHandleIdsMap[sourceNode.id]._connectedSourceHandleIds.splice(index, 1) | |||
| } | |||
| if (type === 'add') | |||
| nodesConnectedSourceOrTargetHandleIdsMap[sourceNode.id]._connectedSourceHandleIds.push(edge.sourceHandle || 'source') | |||
| } | |||
| if (targetNode) { | |||
| if (type === 'remove') | |||
| nodesConnectedSourceOrTargetHandleIdsMap[targetNode.id]._connectedTargetHandleIds = nodesConnectedSourceOrTargetHandleIdsMap[targetNode.id]._connectedTargetHandleIds.filter((handleId: string) => handleId !== edge.targetHandle) | |||
| if (type === 'remove') { | |||
| const index = nodesConnectedSourceOrTargetHandleIdsMap[targetNode.id]._connectedTargetHandleIds.findIndex((handleId: string) => handleId === edge.targetHandle) | |||
| nodesConnectedSourceOrTargetHandleIdsMap[targetNode.id]._connectedTargetHandleIds.splice(index, 1) | |||
| } | |||
| if (type === 'add') | |||
| nodesConnectedSourceOrTargetHandleIdsMap[targetNode.id]._connectedTargetHandleIds.push(edge.targetHandle || 'target') | |||