From f72c03a174ba7be4440f88e645f78f7418e85403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=86=E8=90=8C=E9=97=B7=E6=B2=B9=E7=93=B6?= <253605712@qq.com> Date: Mon, 28 Jul 2025 13:59:34 +0800 Subject: [PATCH] feat: Support selecting variables in conditional filtering in list operations. (#23029) Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: crazywoola <427733928@qq.com> --- api/core/workflow/nodes/list_operator/node.py | 2 +- .../components/filter-condition.tsx | 72 +++++++++++++++---- .../workflow/nodes/list-operator/panel.tsx | 1 + 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/api/core/workflow/nodes/list_operator/node.py b/api/core/workflow/nodes/list_operator/node.py index b91fc622f..d2e022dc9 100644 --- a/api/core/workflow/nodes/list_operator/node.py +++ b/api/core/workflow/nodes/list_operator/node.py @@ -299,7 +299,7 @@ def _endswith(value: str) -> Callable[[str], bool]: def _is(value: str) -> Callable[[str], bool]: - return lambda x: x is value + return lambda x: x == value def _in(value: str | Sequence[str]) -> Callable[[str], bool]: diff --git a/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx b/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx index 0c261a70d..a7ea6d78e 100644 --- a/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx +++ b/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx @@ -1,36 +1,60 @@ 'use client' import type { FC } from 'react' -import React, { useCallback, useMemo } from 'react' +import React, { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import ConditionOperator from '../../if-else/components/condition-list/condition-operator' -import { VarType } from '../../../types' import type { Condition } from '../types' import { ComparisonOperator } from '../../if-else/types' import { comparisonOperatorNotRequireValue, getOperators } from '../../if-else/utils' import SubVariablePicker from './sub-variable-picker' -import Input from '@/app/components/base/input' import { FILE_TYPE_OPTIONS, TRANSFER_METHOD } from '@/app/components/workflow/nodes/constants' import { SimpleSelect as Select } from '@/app/components/base/select' +import Input from '@/app/components/workflow/nodes/_base/components/input-support-select-var' +import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list' +import cn from '@/utils/classnames' +import { VarType } from '../../../types' const optionNameI18NPrefix = 'workflow.nodes.ifElse.optionName' + +const VAR_INPUT_SUPPORTED_KEYS: Record = { + name: VarType.string, + url: VarType.string, + extension: VarType.string, + mime_type: VarType.string, + related_id: VarType.number, +} + type Props = { condition: Condition onChange: (condition: Condition) => void - varType: VarType hasSubVariable: boolean readOnly: boolean + nodeId: string } const FilterCondition: FC = ({ condition = { key: '', comparison_operator: ComparisonOperator.equal, value: '' }, - varType, onChange, hasSubVariable, readOnly, + nodeId, }) => { const { t } = useTranslation() + const [isFocus, setIsFocus] = useState(false) + + const expectedVarType = VAR_INPUT_SUPPORTED_KEYS[condition.key] + const supportVariableInput = !!expectedVarType + + const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { + onlyLeafNodeVar: false, + filterVar: (varPayload) => { + return expectedVarType ? varPayload.type === expectedVarType : true + }, + }) + const isSelect = [ComparisonOperator.in, ComparisonOperator.notIn, ComparisonOperator.allOf].includes(condition.comparison_operator) const isArrayValue = condition.key === 'transfer_method' || condition.key === 'type' + const selectOptions = useMemo(() => { if (isSelect) { if (condition.key === 'type' || condition.comparison_operator === ComparisonOperator.allOf) { @@ -49,6 +73,7 @@ const FilterCondition: FC = ({ } return [] }, [condition.comparison_operator, condition.key, isSelect, t]) + const handleChange = useCallback((key: string) => { return (value: any) => { onChange({ @@ -59,12 +84,14 @@ const FilterCondition: FC = ({ }, [condition, onChange, isArrayValue]) const handleSubVariableChange = useCallback((value: string) => { + const operators = getOperators(expectedVarType ?? VarType.string, { key: value }) + const newOperator = operators.length > 0 ? operators[0] : ComparisonOperator.equal onChange({ key: value, - comparison_operator: getOperators(varType, { key: value })[0], + comparison_operator: newOperator, value: '', }) - }, [onChange, varType]) + }, [onChange, expectedVarType]) return (
@@ -78,7 +105,7 @@ const FilterCondition: FC = ({
= ({ /> {!comparisonOperatorNotRequireValue(condition.comparison_operator) && ( <> - {isSelect && ( + {isSelect ? ( + ) : ( + handleChange('value')(e.target.value)} + readOnly={readOnly} /> )} @@ -110,4 +155,5 @@ const FilterCondition: FC = ({
) } + export default React.memo(FilterCondition) diff --git a/web/app/components/workflow/nodes/list-operator/panel.tsx b/web/app/components/workflow/nodes/list-operator/panel.tsx index d93a79397..9a89629f0 100644 --- a/web/app/components/workflow/nodes/list-operator/panel.tsx +++ b/web/app/components/workflow/nodes/list-operator/panel.tsx @@ -78,6 +78,7 @@ const Panel: FC> = ({ varType={itemVarType} hasSubVariable={hasSubVariable} readOnly={readOnly} + nodeId={id} /> ) : null}