diff --git a/web/src/pages/agent/form/components/dynamic-input-variable.tsx b/web/src/pages/agent/form/components/dynamic-input-variable.tsx
index 82082e6b8..a5781fd16 100644
--- a/web/src/pages/agent/form/components/dynamic-input-variable.tsx
+++ b/web/src/pages/agent/form/components/dynamic-input-variable.tsx
@@ -3,7 +3,7 @@ import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { Button, Collapse, Flex, Form, Input, Select } from 'antd';
import { PropsWithChildren, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
-import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
+import { useBuildVariableOptions } from '../../hooks/use-get-begin-query';
import styles from './index.less';
@@ -21,10 +21,7 @@ const getVariableName = (type: string) =>
const DynamicVariableForm = ({ node }: IProps) => {
const { t } = useTranslation();
- const valueOptions = useBuildComponentIdSelectOptions(
- node?.id,
- node?.parentId,
- );
+ const valueOptions = useBuildVariableOptions(node?.id, node?.parentId);
const form = Form.useFormInstance();
const options = [
diff --git a/web/src/pages/agent/form/components/next-dynamic-input-variable.tsx b/web/src/pages/agent/form/components/next-dynamic-input-variable.tsx
index d22bea406..341b49f37 100644
--- a/web/src/pages/agent/form/components/next-dynamic-input-variable.tsx
+++ b/web/src/pages/agent/form/components/next-dynamic-input-variable.tsx
@@ -20,7 +20,7 @@ import { RAGFlowNodeType } from '@/interfaces/database/flow';
import { Plus, Trash2 } from 'lucide-react';
import { useFieldArray, useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
-import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
+import { useBuildVariableOptions } from '../../hooks/use-get-begin-query';
interface IProps {
node?: RAGFlowNodeType;
@@ -42,10 +42,7 @@ export function DynamicVariableForm({ node }: IProps) {
control: form.control,
});
- const valueOptions = useBuildComponentIdSelectOptions(
- node?.id,
- node?.parentId,
- );
+ const valueOptions = useBuildVariableOptions(node?.id, node?.parentId);
const options = [
{ value: VariableType.Reference, label: t('flow.reference') },
diff --git a/web/src/pages/agent/form/invoke-form/dynamic-variables.tsx b/web/src/pages/agent/form/invoke-form/dynamic-variables.tsx
index 9a67c1f78..f98c04d63 100644
--- a/web/src/pages/agent/form/invoke-form/dynamic-variables.tsx
+++ b/web/src/pages/agent/form/invoke-form/dynamic-variables.tsx
@@ -3,7 +3,7 @@ import { useTranslate } from '@/hooks/common-hooks';
import { DeleteOutlined } from '@ant-design/icons';
import { Button, Collapse, Flex, Input, Select, Table, TableProps } from 'antd';
import { trim } from 'lodash';
-import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
+import { useBuildVariableOptions } from '../../hooks/use-get-begin-query';
import { IInvokeVariable } from '../../interface';
import { useHandleOperateParameters } from './hooks';
@@ -25,7 +25,7 @@ const DynamicVariablesForm = ({ node }: IProps) => {
const nodeId = node?.id;
const { t } = useTranslate('flow');
- const options = useBuildComponentIdSelectOptions(nodeId, node?.parentId);
+ const options = useBuildVariableOptions(nodeId, node?.parentId);
const {
dataSource,
handleAdd,
diff --git a/web/src/pages/agent/form/switch-form/index.less b/web/src/pages/agent/form/switch-form/index.less
deleted file mode 100644
index c5e2c7fe8..000000000
--- a/web/src/pages/agent/form/switch-form/index.less
+++ /dev/null
@@ -1,21 +0,0 @@
-@lightBackgroundColor: rgba(150, 150, 150, 0.07);
-@darkBackgroundColor: rgba(150, 150, 150, 0.12);
-
-.caseCard {
- background-color: @lightBackgroundColor;
-}
-
-.conditionCard {
- background-color: @darkBackgroundColor;
-}
-
-.elseCase {
- background-color: @lightBackgroundColor;
- padding: 12px;
- border-radius: 8px;
-}
-
-.addButton {
- color: rgb(22, 119, 255);
- font-weight: 600;
-}
diff --git a/web/src/pages/agent/form/switch-form/index.tsx b/web/src/pages/agent/form/switch-form/index.tsx
index 222a2baa3..35306375b 100644
--- a/web/src/pages/agent/form/switch-form/index.tsx
+++ b/web/src/pages/agent/form/switch-form/index.tsx
@@ -1,31 +1,179 @@
-import { CloseOutlined } from '@ant-design/icons';
-import { Button, Card, Divider, Form, Input, Select } from 'antd';
+import { FormContainer } from '@/components/form-container';
+import { BlockButton, Button } from '@/components/ui/button';
+import { Card, CardContent } from '@/components/ui/card';
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormMessage,
+} from '@/components/ui/form';
+import { RAGFlowSelect } from '@/components/ui/select';
+import { Textarea } from '@/components/ui/textarea';
+import { ISwitchForm } from '@/interfaces/database/flow';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { X } from 'lucide-react';
import { useMemo } from 'react';
+import { useFieldArray, useForm, useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
+import { z } from 'zod';
import {
Operator,
- SwitchElseTo,
SwitchLogicOperatorOptions,
SwitchOperatorOptions,
} from '../../constant';
import { useBuildFormSelectOptions } from '../../form-hooks';
-import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query';
+import {
+ useBuildComponentIdAndBeginOptions,
+ useBuildVariableOptions,
+} from '../../hooks/use-get-begin-query';
import { IOperatorForm } from '../../interface';
-import { getOtherFieldValues } from '../../utils';
+import { useValues } from './use-values';
-import { ISwitchForm } from '@/interfaces/database/flow';
-import styles from './index.less';
+const ConditionKey = 'conditions';
+const ItemKey = 'items';
-const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
+type ConditionCardsProps = {
+ name: string;
+} & IOperatorForm;
+
+function ConditionCards({ name: parentName, node }: ConditionCardsProps) {
+ const form = useFormContext();
const { t } = useTranslation();
+
+ const componentIdOptions = useBuildComponentIdAndBeginOptions(
+ node?.id,
+ node?.parentId,
+ );
+
+ const switchOperatorOptions = useMemo(() => {
+ return SwitchOperatorOptions.map((x) => ({
+ value: x.value,
+ label: t(`flow.switchOperatorOptions.${x.label}`),
+ }));
+ }, [t]);
+
+ const name = `${parentName}.${ItemKey}`;
+
+ const { fields, remove, append } = useFieldArray({
+ name: name,
+ control: form.control,
+ });
+
+ return (
+
+ {fields.map((field, index) => {
+ return (
+
+
+
+ (
+
+
+
+
+
+
+ )}
+ />
+ (
+
+
+
+
+
+
+ )}
+ />
+
+
+ (
+
+
+
+
+
+
+ )}
+ />
+
+
+
+
+ );
+ })}
+
+ append({ operator: switchOperatorOptions[0].value })}
+ >
+ add
+
+
+
+ );
+}
+
+const SwitchForm = ({ node }: IOperatorForm) => {
+ const { t } = useTranslation();
+ const values = useValues();
+
+ const FormSchema = z.object({
+ conditions: z.array(
+ z
+ .object({
+ logical_operator: z.string(),
+ items: z
+ .array(
+ z.object({
+ cpn_id: z.string(),
+ operator: z.string(),
+ value: z.string().optional(),
+ }),
+ )
+ .optional(),
+ to: z.array(z.string()).optional(),
+ })
+ .optional(),
+ ),
+ });
+
+ const form = useForm({
+ defaultValues: values,
+ resolver: zodResolver(FormSchema),
+ });
+
+ const { fields, remove, append } = useFieldArray({
+ name: ConditionKey,
+ control: form.control,
+ });
+
const buildCategorizeToOptions = useBuildFormSelectOptions(
Operator.Switch,
node?.id,
);
const getSelectedConditionTos = () => {
- const conditions: ISwitchForm['conditions'] =
- form?.getFieldValue('conditions');
+ const conditions: ISwitchForm['conditions'] = form?.getValues('conditions');
return conditions?.filter((x) => !!x).map((x) => x?.to) ?? [];
};
@@ -44,159 +192,52 @@ const SwitchForm = ({ onValuesChange, node, form }: IOperatorForm) => {
}));
}, [t]);
- const componentIdOptions = useBuildComponentIdSelectOptions(
- node?.id,
- node?.parentId,
- );
+ const componentIdOptions = useBuildVariableOptions(node?.id, node?.parentId);
return (
-
- {(fields, { add, remove }) => (
-
- {fields.map((field) => {
- return (
-
{
- remove(field.name);
- }}
- />
- }
- >
-
- {({ getFieldValue }) =>
- getFieldValue(['conditions', field.name, 'items'])
- ?.length > 1 && (
-
-
-
- )
- }
-
-
-
-
-
-
- {(subFields, subOpt) => (
-
- {subFields.map((subField) => (
- {
- subOpt.remove(subField.name);
- }}
- />
- }
- >
-
-
-
-
-
-
-
-
-
-
- ))}
-
-
- )}
-
-
-
- );
- })}
-
-
-
- )}
-
-
-
+
+ {fields.map((field, index) => {
+ return (
+
+ IF
+
+ (
+
+
+
+
+
+
+ )}
+ />
+
+
+
+ );
+ })}
+
+ append({ logical_operator: SwitchLogicOperatorOptions[0] })
+ }
+ >
+ add
+
+
);
};
diff --git a/web/src/pages/agent/form/switch-form/use-values.ts b/web/src/pages/agent/form/switch-form/use-values.ts
new file mode 100644
index 000000000..3323c005a
--- /dev/null
+++ b/web/src/pages/agent/form/switch-form/use-values.ts
@@ -0,0 +1,20 @@
+import { RAGFlowNodeType } from '@/interfaces/database/flow';
+import { isEmpty } from 'lodash';
+import { useMemo } from 'react';
+
+const defaultValues = {
+ conditions: [],
+};
+
+export function useValues(node?: RAGFlowNodeType) {
+ const values = useMemo(() => {
+ const formData = node?.data?.form;
+ if (isEmpty(formData)) {
+ return defaultValues;
+ }
+
+ return formData;
+ }, [node]);
+
+ return values;
+}
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 4abaed98b..2e105b092 100644
--- a/web/src/pages/agent/hooks/use-get-begin-query.tsx
+++ b/web/src/pages/agent/hooks/use-get-begin-query.tsx
@@ -104,14 +104,76 @@ const ExcludedNodes = [
Operator.Note,
];
-export const useBuildComponentIdSelectOptions = (
- nodeId?: string,
- parentId?: string,
-) => {
- const nodes = useGraphStore((state) => state.nodes);
+export function useBuildBeginVariableOptions() {
const getBeginNodeDataQuery = useGetBeginNodeDataQuery();
+ const options = useMemo(() => {
+ const query: BeginQuery[] = getBeginNodeDataQuery();
+ return [
+ {
+ label:
Begin Input,
+ title: 'Begin Input',
+ options: query.map((x) => ({
+ label: x.name,
+ value: `begin@${x.key}`,
+ })),
+ },
+ ];
+ }, [getBeginNodeDataQuery]);
+
+ return options;
+}
+
+export const useBuildVariableOptions = (nodeId?: string) => {
const nodeOutputOptions = useBuildNodeOutputOptions(nodeId);
+ const beginOptions = useBuildBeginVariableOptions();
+
+ const options = useMemo(() => {
+ return [...beginOptions, ...nodeOutputOptions];
+ }, [beginOptions, nodeOutputOptions]);
+
+ return options;
+};
+
+export const useGetComponentLabelByValue = (nodeId: string) => {
+ const options = useBuildVariableOptions(nodeId);
+
+ const flattenOptions = useMemo(() => {
+ return options.reduce
((pre, cur) => {
+ return [...pre, ...cur.options];
+ }, []);
+ }, [options]);
+
+ const getLabel = useCallback(
+ (val?: string) => {
+ return flattenOptions.find((x) => x.value === val)?.label;
+ },
+ [flattenOptions],
+ );
+ return getLabel;
+};
+
+export function useBuildQueryVariableOptions() {
+ const { data } = useFetchAgent();
+ const node = useContext(AgentFormContext);
+ const options = useBuildVariableOptions(node?.id);
+
+ const nextOptions = useMemo(() => {
+ const globalOptions = Object.keys(data?.dsl?.globals ?? {}).map((x) => ({
+ label: x,
+ value: x,
+ }));
+ return [
+ { ...options[0], options: [...options[0]?.options, ...globalOptions] },
+ ...options.slice(1),
+ ];
+ }, [data.dsl.globals, options]);
+
+ return nextOptions;
+}
+
+export function useBuildComponentIdOptions(nodeId?: string, parentId?: string) {
+ const nodes = useGraphStore((state) => state.nodes);
// Limit the nodes inside iteration to only reference peer nodes with the same parentId and other external nodes other than their parent nodes
const filterChildNodesToSameParentOrExternal = useCallback(
@@ -140,57 +202,21 @@ export const useBuildComponentIdSelectOptions = (
.map((x) => ({ label: x.data.name, value: x.id }));
}, [nodes, nodeId, filterChildNodesToSameParentOrExternal]);
- const options = useMemo(() => {
- const query: BeginQuery[] = getBeginNodeDataQuery();
- return [
- {
- label: Begin Input,
- title: 'Begin Input',
- options: query.map((x) => ({
- label: x.name,
- value: `begin@${x.key}`,
- })),
- },
- ...nodeOutputOptions,
- ];
- }, [getBeginNodeDataQuery, nodeOutputOptions]);
-
- return options;
-};
-
-export const useGetComponentLabelByValue = (nodeId: string) => {
- const options = useBuildComponentIdSelectOptions(nodeId);
-
- const flattenOptions = useMemo(() => {
- return options.reduce((pre, cur) => {
- return [...pre, ...cur.options];
- }, []);
- }, [options]);
-
- const getLabel = useCallback(
- (val?: string) => {
- return flattenOptions.find((x) => x.value === val)?.label;
+ return [
+ {
+ label: Component Output,
+ title: 'Component Output',
+ options: componentIdOptions,
},
- [flattenOptions],
- );
- return getLabel;
-};
-
-export function useBuildQueryVariableOptions() {
- const { data } = useFetchAgent();
- const node = useContext(AgentFormContext);
- const options = useBuildComponentIdSelectOptions(node?.id, node?.parentId);
-
- const nextOptions = useMemo(() => {
- const globalOptions = Object.keys(data?.dsl?.globals ?? {}).map((x) => ({
- label: x,
- value: x,
- }));
- return [
- { ...options[0], options: [...options[0]?.options, ...globalOptions] },
- ...options.slice(1),
- ];
- }, [data.dsl.globals, options]);
-
- return nextOptions;
+ ];
+}
+
+export function useBuildComponentIdAndBeginOptions(
+ nodeId?: string,
+ parentId?: string,
+) {
+ const componentIdOptions = useBuildComponentIdOptions(nodeId, parentId);
+ const beginOptions = useBuildBeginVariableOptions();
+
+ return [...beginOptions, ...componentIdOptions];
}