From 6b04b07eb4fd2351e8345c37de302094682df664 Mon Sep 17 00:00:00 2001 From: balibabu Date: Tue, 1 Jul 2025 15:52:14 +0800 Subject: [PATCH] Fixed the issue where variables were not displayed in the switch operator #3221 (#8601) ### What problem does this PR solve? Feat: Fixed the issue where variables were not displayed in the switch operator #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- .../originui/select-with-search.tsx | 172 +++++++++--------- .../pages/agent/canvas/node/switch-node.tsx | 11 +- web/src/pages/agent/constant.tsx | 2 +- .../pages/agent/form/switch-form/index.tsx | 46 ++--- .../form/switch-form/use-watch-change.ts | 5 +- .../tool-form/{constant.ts => constant.tsx} | 3 +- .../pages/agent/hooks/use-get-begin-query.tsx | 37 +++- 7 files changed, 154 insertions(+), 122 deletions(-) rename web/src/pages/agent/form/tool-form/{constant.ts => constant.tsx} (95%) diff --git a/web/src/components/originui/select-with-search.tsx b/web/src/components/originui/select-with-search.tsx index 469802d34..7006fc0b5 100644 --- a/web/src/components/originui/select-with-search.tsx +++ b/web/src/components/originui/select-with-search.tsx @@ -24,6 +24,7 @@ import { PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; +import { cn } from '@/lib/utils'; import { RAGFlowSelectOptionType } from '../ui/select'; const countries = [ @@ -77,96 +78,105 @@ export type SelectWithSearchFlagProps = { options?: SelectWithSearchFlagOptionType[]; value?: string; onChange?(value: string): void; + triggerClassName?: string; }; export const SelectWithSearch = forwardRef< React.ElementRef, SelectWithSearchFlagProps ->(({ value: val = '', onChange, options = countries }, ref) => { - const id = useId(); - const [open, setOpen] = useState(false); - const [value, setValue] = useState(''); +>( + ( + { value: val = '', onChange, options = countries, triggerClassName }, + ref, + ) => { + const id = useId(); + const [open, setOpen] = useState(false); + const [value, setValue] = useState(''); - const handleSelect = useCallback( - (val: string) => { + const handleSelect = useCallback( + (val: string) => { + setValue(val); + setOpen(false); + onChange?.(val); + }, + [onChange], + ); + + useEffect(() => { setValue(val); - setOpen(false); - onChange?.(val); - }, - [onChange], - ); + }, [val]); - useEffect(() => { - setValue(val); - }, [val]); - - return ( - - - - - - - - - No data found. - {options.map((group) => ( - - - {group.options.map((option) => ( - - - {option.label} - + ) : ( + Select value + )} + - ); -}); + {value === option.value && ( + + )} + + ))} + + + ))} + + + + + ); + }, +); SelectWithSearch.displayName = 'SelectWithSearch'; diff --git a/web/src/pages/agent/canvas/node/switch-node.tsx b/web/src/pages/agent/canvas/node/switch-node.tsx index c386731a0..1bd2f45b6 100644 --- a/web/src/pages/agent/canvas/node/switch-node.tsx +++ b/web/src/pages/agent/canvas/node/switch-node.tsx @@ -4,7 +4,7 @@ import { ISwitchCondition, ISwitchNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; import { memo, useCallback } from 'react'; import { NodeHandleId, SwitchOperatorOptions } from '../../constant'; -import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query'; +import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; import { CommonHandle } from './handle'; import { RightHandleStyle } from './handle-icon'; import NodeHeader from './node-header'; @@ -25,12 +25,9 @@ const getConditionKey = (idx: number, length: number) => { const ConditionBlock = ({ condition, nodeId, -}: { - condition: ISwitchCondition; - nodeId: string; -}) => { +}: { condition: ISwitchCondition } & { nodeId: string }) => { const items = condition?.items ?? []; - const getLabel = useGetComponentLabelByValue(nodeId); + const getLabel = useGetVariableLabelByValue(nodeId); const renderOperatorIcon = useCallback((operator?: string) => { const name = SwitchOperatorOptions.find((x) => x.value === operator)?.icon; @@ -83,8 +80,8 @@ function InnerSwitchNode({ id, data, selected }: NodeProps) { {position.condition && ( )} diff --git a/web/src/pages/agent/constant.tsx b/web/src/pages/agent/constant.tsx index 5319eb312..f069b17cf 100644 --- a/web/src/pages/agent/constant.tsx +++ b/web/src/pages/agent/constant.tsx @@ -81,7 +81,7 @@ export enum Operator { Email = 'Email', Iteration = 'Iteration', IterationStart = 'IterationItem', - Code = 'Code', + Code = 'CodeExec', WaitingDialogue = 'WaitingDialogue', Agent = 'Agent', Tool = 'Tool', diff --git a/web/src/pages/agent/form/switch-form/index.tsx b/web/src/pages/agent/form/switch-form/index.tsx index e1f98f352..4882d01e1 100644 --- a/web/src/pages/agent/form/switch-form/index.tsx +++ b/web/src/pages/agent/form/switch-form/index.tsx @@ -1,5 +1,6 @@ import { FormContainer } from '@/components/form-container'; import { IconFont } from '@/components/icon-font'; +import { SelectWithSearch } from '@/components/originui/select-with-search'; import { BlockButton, Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { @@ -12,21 +13,20 @@ import { import { RAGFlowSelect } from '@/components/ui/select'; import { Separator } from '@/components/ui/separator'; import { Textarea } from '@/components/ui/textarea'; -import { ISwitchForm } from '@/interfaces/database/agent'; import { cn } from '@/lib/utils'; import { zodResolver } from '@hookform/resolvers/zod'; +import { toLower } from 'lodash'; import { X } from 'lucide-react'; import { useCallback, useMemo } from 'react'; import { useFieldArray, useForm, useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; import { - Operator, SwitchLogicOperatorOptions, SwitchOperatorOptions, + VariableType, } from '../../constant'; -import { useBuildFormSelectOptions } from '../../form-hooks'; -import { useBuildComponentIdAndBeginOptions } from '../../hooks/use-get-begin-query'; +import { useBuildQueryVariableOptions } from '../../hooks/use-get-begin-query'; import { IOperatorForm } from '../../interface'; import { useValues } from './use-values'; import { useWatchFormChange } from './use-watch-change'; @@ -71,18 +71,24 @@ function useBuildSwitchOperatorOptions() { function ConditionCards({ name: parentName, - node, parentIndex, removeParent, parentLength, }: ConditionCardsProps) { const form = useFormContext(); - const { t } = useTranslation(); - const componentIdOptions = useBuildComponentIdAndBeginOptions( - node?.id, - node?.parentId, - ); + const nextOptions = useBuildQueryVariableOptions(); + + const finalOptions = useMemo(() => { + return nextOptions.map((x) => { + return { + ...x, + options: x.options.filter( + (y) => !toLower(y.type).includes(VariableType.Array), + ), + }; + }); + }, [nextOptions]); const switchOperatorOptions = useBuildSwitchOperatorOptions(); @@ -124,12 +130,11 @@ function ConditionCards({ render={({ field }) => ( - + options={finalOptions} + triggerClassName="w-30 text-background-checked bg-transparent border-none text-ellipsis" + > @@ -224,17 +229,6 @@ const SwitchForm = ({ node }: IOperatorForm) => { control: form.control, }); - const buildCategorizeToOptions = useBuildFormSelectOptions( - Operator.Switch, - node?.id, - ); - - const getSelectedConditionTos = () => { - const conditions: ISwitchForm['conditions'] = form?.getValues('conditions'); - - return conditions?.filter((x) => !!x).map((x) => x?.to) ?? []; - }; - const switchLogicOperatorOptions = useMemo(() => { return SwitchLogicOperatorOptions.map((x) => ({ value: x, diff --git a/web/src/pages/agent/form/switch-form/use-watch-change.ts b/web/src/pages/agent/form/switch-form/use-watch-change.ts index c672ad221..0c8b8259e 100644 --- a/web/src/pages/agent/form/switch-form/use-watch-change.ts +++ b/web/src/pages/agent/form/switch-form/use-watch-change.ts @@ -9,8 +9,9 @@ export function useWatchFormChange(id?: string, form?: UseFormReturn) { useEffect(() => { // Manually triggered form updates are synchronized to the canvas - if (id && form?.formState.isDirty) { - values = form?.getValues(); + console.log('🚀 ~ useWatchFormChange ~ values:', form?.formState.isDirty); + if (id) { + values = form?.getValues() || {}; let nextValues: any = { ...values, conditions: diff --git a/web/src/pages/agent/form/tool-form/constant.ts b/web/src/pages/agent/form/tool-form/constant.tsx similarity index 95% rename from web/src/pages/agent/form/tool-form/constant.ts rename to web/src/pages/agent/form/tool-form/constant.tsx index c10e5056d..708e2542f 100644 --- a/web/src/pages/agent/form/tool-form/constant.ts +++ b/web/src/pages/agent/form/tool-form/constant.tsx @@ -2,7 +2,6 @@ import { Operator } from '../../constant'; import AkShareForm from '../akshare-form'; import ArXivForm from '../arxiv-form'; import BingForm from '../bing-form'; -import CodeForm from '../code-form'; import CrawlerForm from '../crawler-form'; import DeepLForm from '../deepl-form'; import DuckDuckGoForm from '../duckduckgo-form'; @@ -19,7 +18,7 @@ import TavilyForm from './tavily-form'; export const ToolFormConfigMap = { [Operator.Retrieval]: RetrievalForm, - [Operator.Code]: CodeForm, + [Operator.Code]: () =>
, [Operator.DuckDuckGo]: DuckDuckGoForm, [Operator.Wikipedia]: WikipediaForm, [Operator.PubMed]: PubMedForm, diff --git a/web/src/pages/agent/hooks/use-get-begin-query.tsx b/web/src/pages/agent/hooks/use-get-begin-query.tsx index 8a3f89763..45e05b75d 100644 --- a/web/src/pages/agent/hooks/use-get-begin-query.tsx +++ b/web/src/pages/agent/hooks/use-get-begin-query.tsx @@ -24,6 +24,18 @@ export const useGetBeginNodeDataQuery = () => { return getBeginNodeDataQuery; }; +export const useGetBeginNodeDataInputs = () => { + const getNode = useGraphStore((state) => state.getNode); + + const inputs = get(getNode(BeginId), 'data.form.inputs', {}); + + const beginNodeDataInputs = useMemo(() => { + return buildBeginInputListFromObject(inputs); + }, [inputs]); + + return beginNodeDataInputs; +}; + export const useGetBeginNodeDataQueryIsSafe = () => { const [isBeginNodeDataQuerySafe, setIsBeginNodeDataQuerySafe] = useState(false); @@ -152,9 +164,9 @@ export const useBuildVariableOptions = (nodeId?: string, parentId?: string) => { return options; }; -export function useBuildQueryVariableOptions() { +export function useBuildQueryVariableOptions(n?: RAGFlowNodeType) { const { data } = useFetchAgent(); - const node = useContext(AgentFormContext); + const node = useContext(AgentFormContext) || n; const options = useBuildVariableOptions(node?.id, node?.parentId); const nextOptions = useMemo(() => { @@ -170,7 +182,7 @@ export function useBuildQueryVariableOptions() { { ...options[0], options: [...options[0]?.options, ...globalOptions] }, ...options.slice(1), ]; - }, [data.dsl.globals, options]); + }, [data.dsl?.globals, options]); return nextOptions; } @@ -241,3 +253,22 @@ export const useGetComponentLabelByValue = (nodeId: string) => { ); return getLabel; }; + +export function useGetVariableLabelByValue(nodeId: string) { + const { getNode } = useGraphStore((state) => state); + const nextOptions = useBuildQueryVariableOptions(getNode(nodeId)); + + const flattenOptions = useMemo(() => { + return nextOptions.reduce((pre, cur) => { + return [...pre, ...cur.options]; + }, []); + }, [nextOptions]); + + const getLabel = useCallback( + (val?: string) => { + return flattenOptions.find((x) => x.value === val)?.label; + }, + [flattenOptions], + ); + return getLabel; +}