diff --git a/web/app/components/workflow/nodes/_base/components/add-button.tsx b/web/app/components/workflow/nodes/_base/components/add-button.tsx new file mode 100644 index 0000000000..af6a765d31 --- /dev/null +++ b/web/app/components/workflow/nodes/_base/components/add-button.tsx @@ -0,0 +1,28 @@ +'use client' +import type { FC } from 'react' +import React from 'react' +import cn from 'classnames' +import { Plus } from '@/app/components/base/icons/src/vender/line/general' + +type Props = { + className?: string + text: string + onClick: () => void +} + +const AddButton: FC = ({ + className, + text, + onClick, +}) => { + return ( +
+ + {text} +
+ ) +} +export default React.memo(AddButton) diff --git a/web/app/components/workflow/nodes/_base/components/field.tsx b/web/app/components/workflow/nodes/_base/components/field.tsx index 82c05c390c..5b42b0a149 100644 --- a/web/app/components/workflow/nodes/_base/components/field.tsx +++ b/web/app/components/workflow/nodes/_base/components/field.tsx @@ -22,8 +22,8 @@ const Filed: FC = ({ return (
-
-
{title}
+
+
{title}
{tooltip && ( diff --git a/web/app/components/workflow/nodes/if-else/components/condition-item.tsx b/web/app/components/workflow/nodes/if-else/components/condition-item.tsx new file mode 100644 index 0000000000..78dc7ba6bd --- /dev/null +++ b/web/app/components/workflow/nodes/if-else/components/condition-item.tsx @@ -0,0 +1,113 @@ +'use client' +import type { FC } from 'react' +import React, { useCallback } from 'react' +import { useTranslation } from 'react-i18next' +import cn from 'classnames' +import VarReferencePicker from '../../_base/components/variable/var-reference-picker' +import type { Condition } from '@/app/components/workflow/nodes/if-else/types' +import { LogicalOperator } from '@/app/components/workflow/nodes/if-else/types' +import type { ValueSelector } from '@/app/components/workflow/types' +import { Trash03 } from '@/app/components/base/icons/src/vender/line/general' +import { RefreshCw05 } from '@/app/components/base/icons/src/vender/line/arrows' +const i18nPrefix = 'workflow.nodes.ifElse' + +const Line = ( + + + + + + + + + +) + +type ItemProps = { + readonly: boolean + payload: Condition + onChange: (newItem: Condition) => void + canRemove: boolean + onRemove?: () => void + isShowLogicalOperator?: boolean + logicalOperator: LogicalOperator + onLogicalOperatorToggle: () => void +} + +const Item: FC = ({ + readonly, + payload, + onChange, + canRemove, + onRemove = () => { }, + isShowLogicalOperator, + logicalOperator, + onLogicalOperatorToggle, +}) => { + const { t } = useTranslation() + + const handleVarReferenceChange = useCallback((value: ValueSelector) => { + onChange({ + ...payload, + variable_selector: value, + }) + }, [onChange, payload]) + + const handleValueChange = useCallback((e: React.ChangeEvent) => { + onChange({ + ...payload, + value: e.target.value, + }) + }, [onChange, payload]) + + return ( +
+ {isShowLogicalOperator && ( +
+
+ {Line} +
+
{t(`${i18nPrefix}.${logicalOperator === LogicalOperator.and ? 'and' : 'or'}`)}
+ +
+
+ {Line} +
+
+
+ ) + } + +
+ + + + +
{ }} + > + +
+
+
+ + ) +} +export default React.memo(Item) diff --git a/web/app/components/workflow/nodes/if-else/components/condition-list.tsx b/web/app/components/workflow/nodes/if-else/components/condition-list.tsx index b0ddfa9564..292aa5ba50 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-list.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-list.tsx @@ -2,84 +2,26 @@ import type { FC } from 'react' import React, { useCallback } from 'react' import produce from 'immer' -import { useTranslation } from 'react-i18next' import cn from 'classnames' -import VarReferencePicker from '../../_base/components/variable/var-reference-picker' -import type { Condition } from '@/app/components/workflow/nodes/if-else/types' -import type { ValueSelector } from '@/app/components/workflow/types' -import { Trash03 } from '@/app/components/base/icons/src/vender/line/general' -const i18nPrefix = 'workflow.nodes.ifElse' +import Item from './condition-item' +import type { Condition, LogicalOperator } from '@/app/components/workflow/nodes/if-else/types' type Props = { + className?: string readonly: boolean list: Condition[] onChange: (newList: Condition[]) => void -} - -type ItemProps = { - readonly: boolean - payload: Condition - onChange: (newItem: Condition) => void - canRemove: boolean - onRemove?: () => void -} - -const Item: FC = ({ - readonly, - payload, - onChange, - canRemove, - onRemove = () => { }, -}) => { - const { t } = useTranslation() - - const handleVarReferenceChange = useCallback((value: ValueSelector) => { - onChange({ - ...payload, - variable_selector: value, - }) - }, [onChange, payload]) - - const handleValueChange = useCallback((e: React.ChangeEvent) => { - onChange({ - ...payload, - value: e.target.value, - }) - }, [onChange, payload]) - - return ( -
- - - - -
- -
-
- ) + logicalOperator: LogicalOperator + onLogicalOperatorToggle: () => void } const ConditionList: FC = ({ + className, readonly, list, onChange, + logicalOperator, + onLogicalOperatorToggle, }) => { const handleItemChange = useCallback((index: number) => { return (newItem: Condition) => { @@ -99,37 +41,37 @@ const ConditionList: FC = ({ } }, [list, onChange]) + const canRemove = list.length > 1 + if (list.length === 0) return null return ( -
+
- { list.length > 1 && ( - <> -
- AND -
- { - list.slice(1).map((item, i) => ( - - )) - } - ) + list.slice(1).map((item, i) => ( + + ))) }
) diff --git a/web/app/components/workflow/nodes/if-else/panel.tsx b/web/app/components/workflow/nodes/if-else/panel.tsx index fcc0d178c5..91420648a8 100644 --- a/web/app/components/workflow/nodes/if-else/panel.tsx +++ b/web/app/components/workflow/nodes/if-else/panel.tsx @@ -1,5 +1,7 @@ import type { FC } from 'react' import { useTranslation } from 'react-i18next' +import Split from '../_base/components/split' +import AddButton from '../_base/components/add-button' import useConfig from './use-config' import { mockData } from './mock' import ConditionList from './components/condition-list' @@ -14,18 +16,35 @@ const Panel: FC = () => { inputs, handleConditionsChange, handleAddCondition, + handleLogicalOperatorToggle, } = useConfig(mockData) return (
- + <> + + + + + + +
{t(`${i18nPrefix}.elseDescription`)}
diff --git a/web/app/components/workflow/nodes/if-else/use-config.ts b/web/app/components/workflow/nodes/if-else/use-config.ts index 2acf421ff9..f086d31eb7 100644 --- a/web/app/components/workflow/nodes/if-else/use-config.ts +++ b/web/app/components/workflow/nodes/if-else/use-config.ts @@ -1,6 +1,7 @@ import { useCallback, useState } from 'react' import produce from 'immer' -import type { Condition, IfElseNodeType, LogicalOperator } from './types' +import { ComparisonOperator, LogicalOperator } from './types' +import type { Condition, IfElseNodeType } from './types' const useConfig = (initInputs: IfElseNodeType) => { const [inputs, setInputs] = useState(initInputs) @@ -14,16 +15,21 @@ const useConfig = (initInputs: IfElseNodeType) => { }) }, []) - const handleAddCondition = useCallback((condition: Condition) => { + const handleAddCondition = useCallback(() => { const newInputs = produce(inputs, (draft) => { - draft.conditions.push(condition) + draft.conditions.push({ + id: `${Date.now()}`, + variable_selector: [], + comparison_operator: ComparisonOperator.equal, + value: '', + }) }) setInputs(newInputs) }, [inputs]) - const handleLogicalOperatorChange = useCallback((newOperator: LogicalOperator) => { + const handleLogicalOperatorToggle = useCallback(() => { const newInputs = produce(inputs, (draft) => { - draft.logical_operator = newOperator + draft.logical_operator = draft.logical_operator === LogicalOperator.and ? LogicalOperator.or : LogicalOperator.and }) setInputs(newInputs) }, [inputs]) @@ -32,7 +38,7 @@ const useConfig = (initInputs: IfElseNodeType) => { inputs, handleConditionsChange, handleAddCondition, - handleLogicalOperatorChange, + handleLogicalOperatorToggle, } } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index c3a392d488..70c142bb12 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -72,6 +72,9 @@ const translation = { }, ifElse: { conditions: 'Conditions', + if: 'If', + else: 'Else', + elseDescription: 'Used to define the logic that should be executed when the if condition is not met.', and: 'and', or: 'or', comparisonOperator: { @@ -87,6 +90,7 @@ const translation = { 'not null': 'is not null', }, enterValue: 'Enter value', + addCondition: 'Add Condition', }, variableAssigner: { title: 'Assign variables', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index d9e0564afc..07910206e3 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -71,6 +71,9 @@ const translation = { }, ifElse: { conditions: '条件', + if: 'If', + else: 'Else', + elseDescription: '用于定义当 if 条件不满足时应执行的逻辑。', and: 'and', or: 'or', comparisonOperator: { @@ -86,6 +89,7 @@ const translation = { 'not null': '不为空', }, enterValue: '输入值', + addCondition: '添加条件', }, variableAssigner: { title: '变量赋值',