mirror of
https://gitee.com/dify_ai/dify.git
synced 2024-11-30 18:27:53 +08:00
feat: workflow variable aggregator support group (#4811)
Co-authored-by: Yeuoly <admin@srmxy.cn>
This commit is contained in:
parent
18ab63bd37
commit
4b91383efc
@ -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
|
||||
const firstGroupId = toNode.data.advanced_settings?.groups[0].groupId
|
||||
let handleId = 'target'
|
||||
|
||||
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',
|
||||
})
|
||||
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 beforeNodes = getBeforeNodesInSameBranchIncludeParent(nodeId)
|
||||
availableNodes.push(...beforeNodes)
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
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')
|
||||
|
Loading…
Reference in New Issue
Block a user