feat: add elseif to ifelse node (#1378)

This commit is contained in:
heheer
2024-05-07 14:50:58 +08:00
committed by GitHub
parent 9e192c6d11
commit 2053bbdb1b
12 changed files with 756 additions and 423 deletions

View File

@@ -935,6 +935,7 @@
},
"input": {
"Add Input": "Add Input",
"Add Branch": "Add Branch",
"Input Number": "Input: {{length}}",
"add": "",
"description": {

View File

@@ -937,6 +937,7 @@
"Add Input": "添加入参",
"Input Number": "入参: {{length}}",
"add": "添加条件",
"Add Branch": "添加分支",
"description": {
"Background": "你可以添加一些特定内容的介绍,从而更好的识别用户的问题类型。这个内容通常是给模型介绍一个它不知道的内容。",
"HTTP Dynamic Input": "接收前方节点的输出值作为变量这些变量可以被HTTP请求参数使用。",

View File

@@ -47,6 +47,7 @@
"nextjs-node-loader": "^1.1.5",
"nprogress": "^0.2.0",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-day-picker": "^8.7.1",
"react-dom": "18.2.0",
"react-hook-form": "7.43.1",
@@ -72,6 +73,7 @@
"@types/lodash": "^4.14.191",
"@types/node": "^20.8.5",
"@types/react": "18.2.0",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-dom": "18.2.0",
"@types/react-syntax-highlighter": "^15.5.6",
"@types/request-ip": "^0.0.37",

View File

@@ -1,381 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import NodeCard from './render/NodeCard';
import { useTranslation } from 'next-i18next';
import { Box, Button, Flex, background } from '@chakra-ui/react';
import { SmallAddIcon } from '@chakra-ui/icons';
import MyIcon from '@fastgpt/web/components/common/Icon';
import RenderOutput from './render/RenderOutput';
import { NodeInputKeyEnum, WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { NodeProps } from 'reactflow';
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
import {
IfElseConditionType,
IfElseListItemType
} from '@fastgpt/global/core/workflow/template/system/ifElse/type';
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
import { ReferSelector, useReference } from './render/RenderInput/templates/Reference';
import {
VariableConditionEnum,
allConditionList,
arrayConditionList,
booleanConditionList,
numberConditionList
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
import { stringConditionList } from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
import MySelect from '@fastgpt/web/components/common/MySelect';
import MyInput from '@/components/MyInput';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../context';
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
const { nodeId, inputs = [], outputs } = data;
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const condition = useMemo(
() =>
(inputs.find((input) => input.key === NodeInputKeyEnum.condition)
?.value as IfElseConditionType) || 'OR',
[inputs]
);
const ifElseList = useMemo(
() =>
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
?.value as IfElseListItemType[]) || [],
[inputs]
);
const onUpdateIfElseList = useCallback(
(value: IfElseListItemType[]) => {
const ifElseListInput = inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList);
if (!ifElseListInput) return;
onChangeNode({
nodeId,
type: 'updateInput',
key: NodeInputKeyEnum.ifElseList,
value: {
...ifElseListInput,
value
}
});
},
[inputs, nodeId, onChangeNode]
);
const RenderAddCondition = useMemo(() => {
return (
<Button
onClick={() => {
onUpdateIfElseList([
...ifElseList,
{
variable: undefined,
condition: undefined,
value: undefined
}
]);
}}
variant={'whiteBase'}
leftIcon={<SmallAddIcon />}
my={3}
w={'full'}
>
{t('core.module.input.add')}
</Button>
);
}, [ifElseList, onUpdateIfElseList, t]);
return (
<NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={6}>
<RenderOutput nodeId={nodeId} flowOutputList={[outputs[0]]} />
</Box>
<Box py={3} px={4}>
<Box className="nowheel">
{ifElseList.map((item, i) => {
return (
<Box key={i}>
{/* border */}
{i !== 0 && (
<Flex alignItems={'center'} w={'full'} py={'5px'}>
<Box
w={'auto'}
flex={1}
height={'1px'}
style={{
background:
'linear-gradient(90deg, rgba(232, 235, 240, 0.00) 0%, #E8EBF0 100%)'
}}
></Box>
<Flex
px={'2.5'}
color={'primary.600'}
fontWeight={'medium'}
alignItems={'center'}
cursor={'pointer'}
rounded={'md'}
onClick={() => {
const conditionInput = inputs.find(
(input) => input.key === NodeInputKeyEnum.condition
);
if (!conditionInput) return;
onChangeNode({
nodeId,
type: 'updateInput',
key: NodeInputKeyEnum.condition,
value: {
...conditionInput,
value: conditionInput.value === 'OR' ? 'AND' : 'OR'
}
});
}}
>
{condition}
<MyIcon ml={1} boxSize={5} name="change" />
</Flex>
<Box
w={'auto'}
flex={1}
height={'1px'}
style={{
background:
'linear-gradient(90deg, #E8EBF0 0%, rgba(232, 235, 240, 0.00) 100%)'
}}
></Box>
</Flex>
)}
{/* condition list */}
<Flex gap={2} alignItems={'center'}>
{/* variable reference */}
<Box minW={'250px'}>
<Reference
nodeId={nodeId}
variable={item.variable}
onSelect={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === i) {
return {
...ifElse,
variable: e
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* condition select */}
<Box w={'130px'} flex={1}>
<ConditionSelect
condition={item.condition}
variable={item.variable}
onSelect={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === i) {
return {
...ifElse,
condition: e
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* value */}
<Box w={'200px'}>
<ConditionValueInput
value={item.value}
condition={item.condition}
variable={item.variable}
onChange={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === i) {
return {
...ifElse,
value: e
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* delete */}
{ifElseList.length > 1 && (
<MyIcon
ml={2}
boxSize={5}
name="delete"
cursor={'pointer'}
_hover={{ color: 'red.600' }}
color={'myGray.400'}
onClick={() => {
onUpdateIfElseList(ifElseList.filter((_, index) => index !== i));
}}
/>
)}
</Flex>
</Box>
);
})}
</Box>
{RenderAddCondition}
</Box>
<Box px={6} mb={4}>
<RenderOutput nodeId={nodeId} flowOutputList={[outputs[1]]} />
</Box>
</NodeCard>
);
};
export default React.memo(NodeIfElse);
const Reference = ({
nodeId,
variable,
onSelect
}: {
nodeId: string;
variable?: ReferenceValueProps;
onSelect: (e: ReferenceValueProps) => void;
}) => {
const { t } = useTranslation();
const { referenceList, formatValue } = useReference({
nodeId,
valueType: WorkflowIOValueTypeEnum.any,
value: variable
});
return (
<ReferSelector
placeholder={t('选择引用变量')}
list={referenceList}
value={formatValue}
onSelect={onSelect}
/>
);
};
/* Different data types have different options */
const ConditionSelect = ({
condition,
variable,
onSelect
}: {
condition?: VariableConditionEnum;
variable?: ReferenceValueProps;
onSelect: (e: VariableConditionEnum) => void;
}) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get condition type
const valueType = useMemo(() => {
if (!variable) return;
const node = nodeList.find((node) => node.nodeId === variable[0]);
if (!node) return WorkflowIOValueTypeEnum.any;
const output = node.outputs.find((item) => item.id === variable[1]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
}, [nodeList, variable]);
const conditionList = useMemo(() => {
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;
if (valueType === WorkflowIOValueTypeEnum.number) return numberConditionList;
if (valueType === WorkflowIOValueTypeEnum.boolean) return booleanConditionList;
if (
valueType === WorkflowIOValueTypeEnum.chatHistory ||
valueType === WorkflowIOValueTypeEnum.datasetQuote ||
valueType === WorkflowIOValueTypeEnum.dynamic ||
valueType === WorkflowIOValueTypeEnum.selectApp ||
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
valueType === WorkflowIOValueTypeEnum.arrayObject ||
valueType === WorkflowIOValueTypeEnum.arrayString ||
valueType === WorkflowIOValueTypeEnum.object
)
return arrayConditionList;
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
return [];
}, [valueType]);
return (
<MySelect
w={'100%'}
list={conditionList}
value={condition}
onchange={onSelect}
placeholder="选择条件"
></MySelect>
);
};
/*
Different condition can be entered differently
empty, notEmpty: forbid input
boolean type: select true/false
*/
const ConditionValueInput = ({
value = '',
variable,
condition,
onChange
}: {
value?: string;
variable?: ReferenceValueProps;
condition?: VariableConditionEnum;
onChange: (e: string) => void;
}) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get value type
const valueType = useMemo(() => {
if (!variable) return;
const node = nodeList.find((node) => node.nodeId === variable[0]);
if (!node) return WorkflowIOValueTypeEnum.any;
const output = node.outputs.find((item) => item.id === variable[1]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
}, [nodeList, variable]);
if (valueType === WorkflowIOValueTypeEnum.boolean) {
return (
<MySelect
list={[
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' }
]}
onchange={onChange}
value={value}
placeholder={'选择值'}
/>
);
} else {
return (
<MyInput
value={value}
placeholder={'输入值'}
w={'100%'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
onChange={(e) => onChange(e.target.value)}
/>
);
}
};

View File

@@ -0,0 +1,412 @@
import { Box, Button, Flex } from '@chakra-ui/react';
import { DraggableProvided, DraggableStateSnapshot } from 'react-beautiful-dnd';
import Container from '../../components/Container';
import { DragHandleIcon, MinusIcon, SmallAddIcon } from '@chakra-ui/icons';
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { ReferenceValueProps } from '@fastgpt/global/core/workflow/type/io';
import { useTranslation } from 'react-i18next';
import { ReferSelector, useReference } from '../render/RenderInput/templates/Reference';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import {
VariableConditionEnum,
allConditionList,
arrayConditionList,
booleanConditionList,
numberConditionList,
stringConditionList
} from '@fastgpt/global/core/workflow/template/system/ifElse/constant';
import { useContextSelector } from 'use-context-selector';
import React, { useMemo } from 'react';
import { WorkflowContext } from '../../../context';
import MySelect from '@fastgpt/web/components/common/MySelect';
import MyInput from '@/components/MyInput';
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
import { SourceHandle } from '../render/Handle';
import { Position, useReactFlow } from 'reactflow';
const ListItem = ({
provided,
snapshot,
conditionIndex,
conditionItem,
ifElseList,
onUpdateIfElseList,
nodeId
}: {
provided: DraggableProvided;
snapshot: DraggableStateSnapshot;
conditionIndex: number;
conditionItem: IfElseListItemType;
ifElseList: IfElseListItemType[];
onUpdateIfElseList: (value: IfElseListItemType[]) => void;
nodeId: string;
}) => {
const { t } = useTranslation();
const { getZoom } = useReactFlow();
return (
<Box
ref={provided.innerRef}
{...provided.draggableProps}
style={{
...provided.draggableProps.style,
opacity: snapshot.isDragging ? 0.8 : 1
}}
>
<Flex
alignItems={'center'}
position={'relative'}
transform={snapshot.isDragging ? `scale(${getZoom()})` : ''}
transformOrigin={'top left'}
>
<Container w={snapshot.isDragging ? '' : 'full'} className="nodrag">
<Flex mb={4} alignItems={'center'}>
<Box {...provided.dragHandleProps}>
<DragHandleIcon color={'blackAlpha.600'} />
</Box>
<Box color={'black'} fontSize={'lg'} ml={2}>
{conditionIndex === 0 ? 'IF' : 'ELSE IF'}
</Box>
<Flex
px={'2.5'}
color={'primary.600'}
fontWeight={'medium'}
alignItems={'center'}
cursor={'pointer'}
rounded={'md'}
onClick={() => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
condition: ifElse.condition === 'AND' ? 'OR' : 'AND'
};
}
return ifElse;
})
);
}}
>
{conditionItem.condition}
<MyIcon ml={1} boxSize={5} name="change" />
</Flex>
<Box flex={1}></Box>
{ifElseList.length > 1 && (
<MyIcon
ml={2}
boxSize={5}
name="delete"
cursor={'pointer'}
_hover={{ color: 'red.600' }}
color={'myGray.400'}
onClick={() => {
onUpdateIfElseList(ifElseList.filter((_, index) => index !== conditionIndex));
}}
/>
)}
</Flex>
<Box>
{conditionItem.list?.map((item, i) => {
return (
<Box key={i}>
{/* condition list */}
<Flex gap={2} mb={2} alignItems={'center'}>
{/* variable reference */}
<Box minW={'250px'}>
<Reference
nodeId={nodeId}
variable={item.variable}
onSelect={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.map((item, index) => {
if (index === i) {
return {
...item,
variable: e
};
}
return item;
})
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* condition select */}
<Box w={'130px'} flex={1}>
<ConditionSelect
condition={item.condition}
variable={item.variable}
onSelect={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.map((item, index) => {
if (index === i) {
return {
...item,
condition: e
};
}
return item;
})
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* value */}
<Box w={'200px'}>
<ConditionValueInput
value={item.value}
condition={item.condition}
variable={item.variable}
onChange={(e) => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.map((item, index) => {
if (index === i) {
return {
...item,
value: e
};
}
return item;
})
};
}
return ifElse;
})
);
}}
/>
</Box>
{/* delete */}
{conditionItem.list.length > 1 && (
<MinusIcon
ml={2}
boxSize={3}
name="delete"
cursor={'pointer'}
_hover={{ color: 'red.600' }}
color={'myGray.400'}
onClick={() => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.filter((_, index) => index !== i)
};
}
return ifElse;
})
);
}}
/>
)}
</Flex>
</Box>
);
})}
</Box>
<Button
onClick={() => {
onUpdateIfElseList(
ifElseList.map((ifElse, index) => {
if (index === conditionIndex) {
return {
...ifElse,
list: ifElse.list.concat({
variable: undefined,
condition: undefined,
value: undefined
})
};
}
return ifElse;
})
);
}}
variant={'link'}
leftIcon={<SmallAddIcon />}
my={3}
color={'primary.600'}
>
{t('core.module.input.add')}
</Button>
</Container>
{!snapshot.isDragging && (
<SourceHandle
nodeId={nodeId}
handleId={getHandleId(nodeId, 'source', 'IF' + conditionIndex.toString())}
position={Position.Right}
translate={[18, 0]}
/>
)}
</Flex>
</Box>
);
};
export default React.memo(ListItem);
const Reference = ({
nodeId,
variable,
onSelect
}: {
nodeId: string;
variable?: ReferenceValueProps;
onSelect: (e: ReferenceValueProps) => void;
}) => {
const { t } = useTranslation();
const { referenceList, formatValue } = useReference({
nodeId,
valueType: WorkflowIOValueTypeEnum.any,
value: variable
});
return (
<ReferSelector
placeholder={t('选择引用变量')}
list={referenceList}
value={formatValue}
onSelect={onSelect}
/>
);
};
/* Different data types have different options */
const ConditionSelect = ({
condition,
variable,
onSelect
}: {
condition?: VariableConditionEnum;
variable?: ReferenceValueProps;
onSelect: (e: VariableConditionEnum) => void;
}) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get condition type
const valueType = useMemo(() => {
if (!variable) return;
const node = nodeList.find((node) => node.nodeId === variable[0]);
if (!node) return WorkflowIOValueTypeEnum.any;
const output = node.outputs.find((item) => item.id === variable[1]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
}, [nodeList, variable]);
const conditionList = useMemo(() => {
if (valueType === WorkflowIOValueTypeEnum.string) return stringConditionList;
if (valueType === WorkflowIOValueTypeEnum.number) return numberConditionList;
if (valueType === WorkflowIOValueTypeEnum.boolean) return booleanConditionList;
if (
valueType === WorkflowIOValueTypeEnum.chatHistory ||
valueType === WorkflowIOValueTypeEnum.datasetQuote ||
valueType === WorkflowIOValueTypeEnum.dynamic ||
valueType === WorkflowIOValueTypeEnum.selectApp ||
valueType === WorkflowIOValueTypeEnum.arrayBoolean ||
valueType === WorkflowIOValueTypeEnum.arrayNumber ||
valueType === WorkflowIOValueTypeEnum.arrayObject ||
valueType === WorkflowIOValueTypeEnum.arrayString ||
valueType === WorkflowIOValueTypeEnum.object
)
return arrayConditionList;
if (valueType === WorkflowIOValueTypeEnum.any) return allConditionList;
return [];
}, [valueType]);
return (
<MySelect
w={'100%'}
list={conditionList}
value={condition}
onchange={onSelect}
placeholder="选择条件"
/>
);
};
/*
Different condition can be entered differently
empty, notEmpty: forbid input
boolean type: select true/false
*/
const ConditionValueInput = ({
value = '',
variable,
condition,
onChange
}: {
value?: string;
variable?: ReferenceValueProps;
condition?: VariableConditionEnum;
onChange: (e: string) => void;
}) => {
const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
// get value type
const valueType = useMemo(() => {
if (!variable) return;
const node = nodeList.find((node) => node.nodeId === variable[0]);
if (!node) return WorkflowIOValueTypeEnum.any;
const output = node.outputs.find((item) => item.id === variable[1]);
if (!output) return WorkflowIOValueTypeEnum.any;
return output.valueType;
}, [nodeList, variable]);
if (valueType === WorkflowIOValueTypeEnum.boolean) {
return (
<MySelect
list={[
{ label: 'True', value: 'true' },
{ label: 'False', value: 'false' }
]}
onchange={onChange}
value={value}
placeholder={'选择值'}
/>
);
} else {
return (
<MyInput
value={value}
placeholder={'输入值'}
w={'100%'}
bg={'white'}
isDisabled={
condition === VariableConditionEnum.isEmpty ||
condition === VariableConditionEnum.isNotEmpty
}
onChange={(e) => onChange(e.target.value)}
/>
);
}
};

View File

@@ -0,0 +1,161 @@
import React, { useCallback, useMemo, useState } from 'react';
import NodeCard from '../render/NodeCard';
import { useTranslation } from 'next-i18next';
import { Box, Button, Flex } from '@chakra-ui/react';
import { NodeInputKeyEnum } from '@fastgpt/global/core/workflow/constants';
import { NodeProps, Position } from 'reactflow';
import { FlowNodeItemType } from '@fastgpt/global/core/workflow/type';
import { IfElseListItemType } from '@fastgpt/global/core/workflow/template/system/ifElse/type';
import { useContextSelector } from 'use-context-selector';
import { WorkflowContext } from '../../../context';
import Container from '../../components/Container';
import { DragDropContext, DragStart, Draggable, DropResult, Droppable } from 'react-beautiful-dnd';
import { SourceHandle } from '../render/Handle';
import { getHandleId } from '@fastgpt/global/core/workflow/utils';
import ListItem from './ListItem';
const NodeIfElse = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
const { t } = useTranslation();
const { nodeId, inputs = [] } = data;
const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
const [draggingItemHeight, setDraggingItemHeight] = useState(0);
const ifElseList = useMemo(
() =>
(inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList)
?.value as IfElseListItemType[]) || [],
[inputs]
);
const onUpdateIfElseList = useCallback(
(value: IfElseListItemType[]) => {
const ifElseListInput = inputs.find((input) => input.key === NodeInputKeyEnum.ifElseList);
if (!ifElseListInput) return;
onChangeNode({
nodeId,
type: 'updateInput',
key: NodeInputKeyEnum.ifElseList,
value: {
...ifElseListInput,
value
}
});
},
[inputs, nodeId, onChangeNode]
);
const reorder = (list: IfElseListItemType[], startIndex: number, endIndex: number) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const onDragStart = (start: DragStart) => {
const draggingNode = document.querySelector(`[data-rbd-draggable-id="${start.draggableId}"]`);
setDraggingItemHeight(draggingNode?.getBoundingClientRect().height || 0);
};
const onDragEnd = (result: DropResult) => {
if (!result.destination) {
return;
}
const newList = reorder(ifElseList, result.source.index, result.destination.index);
onUpdateIfElseList(newList);
setDraggingItemHeight(0);
};
return (
<NodeCard selected={selected} maxW={'1000px'} {...data}>
<Box px={4}>
<DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}>
<Droppable
droppableId="droppable"
renderClone={(provided, snapshot, rubric) => (
<ListItem
provided={provided}
snapshot={snapshot}
conditionItem={ifElseList[rubric.source.index]}
conditionIndex={rubric.source.index}
ifElseList={ifElseList}
onUpdateIfElseList={onUpdateIfElseList}
nodeId={nodeId}
/>
)}
>
{(provided, snapshot) => (
<Box {...provided.droppableProps} ref={provided.innerRef}>
{ifElseList.map((conditionItem, conditionIndex) => (
<Draggable
key={conditionIndex}
draggableId={conditionIndex.toString()}
index={conditionIndex}
>
{(provided, snapshot) => (
<ListItem
provided={provided}
snapshot={snapshot}
conditionItem={conditionItem}
conditionIndex={conditionIndex}
ifElseList={ifElseList}
onUpdateIfElseList={onUpdateIfElseList}
nodeId={nodeId}
/>
)}
</Draggable>
))}
<Box height={draggingItemHeight} />
</Box>
)}
</Droppable>
</DragDropContext>
<Container position={'relative'}>
<Flex alignItems={'center'}>
<Box color={'black'} fontSize={'lg'} ml={2}>
ELSE
</Box>
<SourceHandle
nodeId={nodeId}
handleId={getHandleId(nodeId, 'source', 'ELSE')}
position={Position.Right}
translate={[26, 0]}
/>
</Flex>
</Container>
</Box>
<Box py={3} px={6}>
<Button
variant={'whiteBase'}
w={'full'}
onClick={() => {
const ifElseListInput = inputs.find(
(input) => input.key === NodeInputKeyEnum.ifElseList
);
if (!ifElseListInput) return;
onUpdateIfElseList([
...ifElseList,
{
condition: 'AND',
list: [
{
variable: undefined,
condition: undefined,
value: undefined
}
]
}
]);
}}
>
{t('core.module.input.Add Branch')}
</Button>
</Box>
</NodeCard>
);
};
export default React.memo(NodeIfElse);