From 850e2180517ce50fc90a0608a908c27fa7927624 Mon Sep 17 00:00:00 2001 From: balibabu Date: Tue, 4 Mar 2025 19:31:32 +0800 Subject: [PATCH] Feat: Render DynamicCategorize with shadcn-ui. #3221 (#5610) ### What problem does this PR solve? Feat: Render DynamicCategorize with shadcn-ui. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- web/src/components/large-model-form-field.tsx | 31 ++ web/src/pages/agent/form-sheet/index.tsx | 208 ------------ web/src/pages/agent/form-sheet/next.tsx | 5 +- .../agent/form-sheet/use-form-config-map.tsx | 11 +- .../categorize-form/dynamic-categorize.tsx | 306 ++++++++++-------- .../agent/form/categorize-form/index.less | 13 - .../agent/form/categorize-form/index.tsx | 54 ++-- .../pages/agent/form/message-form/index.less | 16 - 8 files changed, 239 insertions(+), 405 deletions(-) create mode 100644 web/src/components/large-model-form-field.tsx delete mode 100644 web/src/pages/agent/form-sheet/index.tsx delete mode 100644 web/src/pages/agent/form/categorize-form/index.less delete mode 100644 web/src/pages/agent/form/message-form/index.less diff --git a/web/src/components/large-model-form-field.tsx b/web/src/components/large-model-form-field.tsx new file mode 100644 index 00000000..f6b2a431 --- /dev/null +++ b/web/src/components/large-model-form-field.tsx @@ -0,0 +1,31 @@ +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import { useFormContext } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { NextLLMSelect } from './llm-select'; + +export function LargeModelFormField() { + const form = useFormContext(); + const { t } = useTranslation(); + + return ( + ( + + {t('chat.model')} + + + + + + )} + /> + ); +} diff --git a/web/src/pages/agent/form-sheet/index.tsx b/web/src/pages/agent/form-sheet/index.tsx deleted file mode 100644 index e48d6910..00000000 --- a/web/src/pages/agent/form-sheet/index.tsx +++ /dev/null @@ -1,208 +0,0 @@ -import { useTranslate } from '@/hooks/common-hooks'; -import { IModalProps } from '@/interfaces/common'; -import { Flex, Form, Input } from 'antd'; -import { get, isPlainObject, lowerFirst } from 'lodash'; -import { Play } from 'lucide-react'; -import { useEffect, useRef } from 'react'; -import { BeginId, Operator, operatorMap } from '../constant'; -import AkShareForm from '../form/akshare-form'; -import AnswerForm from '../form/answer-form'; -import ArXivForm from '../form/arxiv-form'; -import BaiduFanyiForm from '../form/baidu-fanyi-form'; -import BaiduForm from '../form/baidu-form'; -import BeginForm from '../form/begin-form'; -import BingForm from '../form/bing-form'; -import CategorizeForm from '../form/categorize-form'; -import CrawlerForm from '../form/crawler-form'; -import DeepLForm from '../form/deepl-form'; -import DuckDuckGoForm from '../form/duckduckgo-form'; -import EmailForm from '../form/email-form'; -import ExeSQLForm from '../form/exesql-form'; -import GenerateForm from '../form/generate-form'; -import GithubForm from '../form/github-form'; -import GoogleForm from '../form/google-form'; -import GoogleScholarForm from '../form/google-scholar-form'; -import InvokeForm from '../form/invoke-form'; -import Jin10Form from '../form/jin10-form'; -import KeywordExtractForm from '../form/keyword-extract-form'; -import MessageForm from '../form/message-form'; -import PubMedForm from '../form/pubmed-form'; -import QWeatherForm from '../form/qweather-form'; -import RelevantForm from '../form/relevant-form'; -import RetrievalForm from '../form/retrieval-form/next'; -import RewriteQuestionForm from '../form/rewrite-question-form'; -import SwitchForm from '../form/switch-form'; -import TemplateForm from '../form/template-form'; -import TuShareForm from '../form/tushare-form'; -import WenCaiForm from '../form/wencai-form'; -import WikipediaForm from '../form/wikipedia-form'; -import YahooFinanceForm from '../form/yahoo-finance-form'; -import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks'; -import OperatorIcon from '../operator-icon'; -import { - buildCategorizeListFromObject, - needsSingleStepDebugging, -} from '../utils'; - -import { Sheet, SheetContent, SheetHeader } from '@/components/ui/sheet'; -import { RAGFlowNodeType } from '@/interfaces/database/flow'; -import { FlowFormContext } from '../context'; -import { RunTooltip } from '../flow-tooltip'; -import IterationForm from '../form/iteration-from'; - -import styles from './index.less'; - -interface IProps { - node?: RAGFlowNodeType; - singleDebugDrawerVisible: IModalProps['visible']; - hideSingleDebugDrawer: IModalProps['hideModal']; - showSingleDebugDrawer: IModalProps['showModal']; -} - -const FormMap = { - [Operator.Begin]: BeginForm, - [Operator.Retrieval]: RetrievalForm, - [Operator.Generate]: GenerateForm, - [Operator.Answer]: AnswerForm, - [Operator.Categorize]: CategorizeForm, - [Operator.Message]: MessageForm, - [Operator.Relevant]: RelevantForm, - [Operator.RewriteQuestion]: RewriteQuestionForm, - [Operator.Baidu]: BaiduForm, - [Operator.DuckDuckGo]: DuckDuckGoForm, - [Operator.KeywordExtract]: KeywordExtractForm, - [Operator.Wikipedia]: WikipediaForm, - [Operator.PubMed]: PubMedForm, - [Operator.ArXiv]: ArXivForm, - [Operator.Google]: GoogleForm, - [Operator.Bing]: BingForm, - [Operator.GoogleScholar]: GoogleScholarForm, - [Operator.DeepL]: DeepLForm, - [Operator.GitHub]: GithubForm, - [Operator.BaiduFanyi]: BaiduFanyiForm, - [Operator.QWeather]: QWeatherForm, - [Operator.ExeSQL]: ExeSQLForm, - [Operator.Switch]: SwitchForm, - [Operator.WenCai]: WenCaiForm, - [Operator.AkShare]: AkShareForm, - [Operator.YahooFinance]: YahooFinanceForm, - [Operator.Jin10]: Jin10Form, - [Operator.TuShare]: TuShareForm, - [Operator.Crawler]: CrawlerForm, - [Operator.Invoke]: InvokeForm, - [Operator.Concentrator]: () => <>, - [Operator.Note]: () => <>, - [Operator.Template]: TemplateForm, - [Operator.Email]: EmailForm, - [Operator.Iteration]: IterationForm, - [Operator.IterationStart]: () => <>, -}; - -const EmptyContent = () =>
; - -const FormDrawer = ({ - visible, - hideModal, - node, - singleDebugDrawerVisible, - hideSingleDebugDrawer, - showSingleDebugDrawer, -}: IModalProps & IProps) => { - const operatorName: Operator = node?.data.label as Operator; - const OperatorForm = FormMap[operatorName] ?? EmptyContent; - const [form] = Form.useForm(); - const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({ - id: node?.id, - data: node?.data, - }); - const previousId = useRef(node?.id); - - const { t } = useTranslate('flow'); - - const { handleValuesChange } = useHandleFormValuesChange(node?.id); - - useEffect(() => { - if (visible) { - if (node?.id !== previousId.current) { - form.resetFields(); - } - - if (operatorName === Operator.Categorize) { - const items = buildCategorizeListFromObject( - get(node, 'data.form.category_description', {}), - ); - const formData = node?.data?.form; - if (isPlainObject(formData)) { - form.setFieldsValue({ ...formData, items }); - } - } else { - form.setFieldsValue(node?.data?.form); - } - previousId.current = node?.id; - } - }, [visible, form, node?.data?.form, node?.id, node, operatorName]); - - return ( - - - - - - - - - {node?.id === BeginId ? ( - {t(BeginId)} - ) : ( - - )} - - - {needsSingleStepDebugging(operatorName) && ( - - - - )} - {/* */} - - - {t(`${lowerFirst(operatorName)}Description`)} - - - -
- {visible && ( - - - - )} -
-
- {/* {singleDebugDrawerVisible && ( - - )} */} -
- ); -}; - -export default FormDrawer; diff --git a/web/src/pages/agent/form-sheet/next.tsx b/web/src/pages/agent/form-sheet/next.tsx index d7dd03a5..e5030b6e 100644 --- a/web/src/pages/agent/form-sheet/next.tsx +++ b/web/src/pages/agent/form-sheet/next.tsx @@ -8,6 +8,7 @@ import { import { useTranslate } from '@/hooks/common-hooks'; import { IModalProps } from '@/interfaces/common'; import { RAGFlowNodeType } from '@/interfaces/database/flow'; +import { cn } from '@/lib/utils'; import { zodResolver } from '@hookform/resolvers/zod'; import { get, isPlainObject, lowerFirst } from 'lodash'; import { Play, X } from 'lucide-react'; @@ -94,9 +95,9 @@ const FormSheet = ({ return ( - + -
+
void; otherNames?: string[]; - validate(errors: string[]): void; + validate(error?: string): void; } const getOtherFieldValues = ( - form: FormInstance, + form: UseFormReturn, formListName: string = 'items', - field: FormListFieldData, + index: number, latestField: string, ) => - (form.getFieldValue([formListName]) ?? []) + (form.getValues(formListName) ?? []) .map((x: any) => x[latestField]) .filter( (x: string) => - x !== form.getFieldValue([formListName, field.name, latestField]), + x !== form.getValues(`${formListName}.${index}.${latestField}`), ); const NameInput = ({ @@ -61,15 +67,16 @@ const NameInput = ({ const handleNameChange: ChangeEventHandler = useCallback( (e) => { const val = e.target.value; - // trigger validation - if (otherNames?.some((x) => x === val)) { - validate([t('nameRepeatedMsg')]); - } else if (trim(val) === '') { - validate([t('nameRequiredMsg')]); - } else { - validate([]); - } setName(val); + const trimmedVal = trim(val); + // trigger validation + if (otherNames?.some((x) => x === trimmedVal)) { + validate(t('nameRepeatedMsg')); + } else if (trimmedVal === '') { + validate(t('nameRequiredMsg')); + } else { + validate(''); + } }, [otherNames, validate, t], ); @@ -97,128 +104,161 @@ const NameInput = ({ ); }; -const FormSet = ({ nodeId, field }: IProps & { field: FormListFieldData }) => { - const form = Form.useFormInstance(); +const FormSet = ({ nodeId, index }: IProps & { index: number }) => { + const form = useFormContext(); const { t } = useTranslate('flow'); const buildCategorizeToOptions = useBuildFormSelectOptions( Operator.Categorize, nodeId, ); + const buildFieldName = useCallback( + (name: string) => { + return `items.${index}.${name}`; + }, + [index], + ); + return ( -
- - - form.setFields([ - { - name: ['items', field.name, 'name'], - errors, - }, - ]) - } - > - - - - - - - - - - +
+ ( + + {t('categoryName')} + + { + const fieldName = buildFieldName('name'); + if (error) { + form.setError(fieldName, { message: error }); + } else { + form.clearErrors(fieldName); + } + }} + > + + + + )} + /> + ( + + {t('description')} + +