### What problem does this PR solve? Feat: Add DynamicVariableForm with shadcn-ui. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.17.0
| @@ -6,7 +6,7 @@ import { | |||
| } from '@xyflow/react'; | |||
| import '@xyflow/react/dist/style.css'; | |||
| // import ChatDrawer from '../chat/drawer'; | |||
| import FormDrawer from '../form-drawer'; | |||
| import FormDrawer from '../form-drawer/next'; | |||
| import { | |||
| useHandleDrop, | |||
| useSelectCanvasData, | |||
| @@ -1,7 +1,6 @@ | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import { CloseOutlined } from '@ant-design/icons'; | |||
| import { Drawer, Flex, Form, Input } from 'antd'; | |||
| import { Flex, Form, Input } from 'antd'; | |||
| import { get, isPlainObject, lowerFirst } from 'lodash'; | |||
| import { Play } from 'lucide-react'; | |||
| import { useEffect, useRef } from 'react'; | |||
| @@ -30,7 +29,7 @@ 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'; | |||
| 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'; | |||
| @@ -42,15 +41,15 @@ import { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks'; | |||
| import OperatorIcon from '../operator-icon'; | |||
| import { | |||
| buildCategorizeListFromObject, | |||
| getDrawerWidth, | |||
| needsSingleStepDebugging, | |||
| } from '../utils'; | |||
| import SingleDebugDrawer from './single-debug-drawer'; | |||
| 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 { | |||
| @@ -144,72 +143,65 @@ const FormDrawer = ({ | |||
| }, [visible, form, node?.data?.form, node?.id, node, operatorName]); | |||
| return ( | |||
| <Drawer | |||
| title={ | |||
| <Flex vertical> | |||
| <Flex gap={'middle'} align="center"> | |||
| <OperatorIcon | |||
| name={operatorName} | |||
| color={operatorMap[operatorName]?.color} | |||
| ></OperatorIcon> | |||
| <Flex align="center" gap={'small'} flex={1}> | |||
| <label htmlFor="" className={styles.title}> | |||
| {t('title')} | |||
| </label> | |||
| {node?.id === BeginId ? ( | |||
| <span>{t(BeginId)}</span> | |||
| ) : ( | |||
| <Input | |||
| value={name} | |||
| onBlur={handleNameBlur} | |||
| onChange={handleNameChange} | |||
| ></Input> | |||
| <Sheet onOpenChange={hideModal} open={visible}> | |||
| <SheetContent> | |||
| <SheetHeader> | |||
| <Flex vertical> | |||
| <Flex gap={'middle'} align="center"> | |||
| <OperatorIcon | |||
| name={operatorName} | |||
| color={operatorMap[operatorName]?.color} | |||
| ></OperatorIcon> | |||
| <Flex align="center" gap={'small'} flex={1}> | |||
| <label htmlFor="" className={styles.title}> | |||
| {t('title')} | |||
| </label> | |||
| {node?.id === BeginId ? ( | |||
| <span>{t(BeginId)}</span> | |||
| ) : ( | |||
| <Input | |||
| value={name} | |||
| onBlur={handleNameBlur} | |||
| onChange={handleNameChange} | |||
| ></Input> | |||
| )} | |||
| </Flex> | |||
| {needsSingleStepDebugging(operatorName) && ( | |||
| <RunTooltip> | |||
| <Play | |||
| className="size-5 cursor-pointer" | |||
| onClick={showSingleDebugDrawer} | |||
| /> | |||
| </RunTooltip> | |||
| )} | |||
| {/* <CloseOutlined onClick={hideModal} /> */} | |||
| </Flex> | |||
| {needsSingleStepDebugging(operatorName) && ( | |||
| <RunTooltip> | |||
| <Play | |||
| className="size-5 cursor-pointer" | |||
| onClick={showSingleDebugDrawer} | |||
| /> | |||
| </RunTooltip> | |||
| )} | |||
| <CloseOutlined onClick={hideModal} /> | |||
| <span className={styles.operatorDescription}> | |||
| {t(`${lowerFirst(operatorName)}Description`)} | |||
| </span> | |||
| </Flex> | |||
| <span className={styles.operatorDescription}> | |||
| {t(`${lowerFirst(operatorName)}Description`)} | |||
| </span> | |||
| </Flex> | |||
| } | |||
| placement="right" | |||
| onClose={hideModal} | |||
| open={visible} | |||
| getContainer={false} | |||
| mask={false} | |||
| width={getDrawerWidth()} | |||
| closeIcon={null} | |||
| rootClassName={styles.formDrawer} | |||
| > | |||
| <section className={styles.formWrapper}> | |||
| {visible && ( | |||
| <FlowFormContext.Provider value={node}> | |||
| <OperatorForm | |||
| onValuesChange={handleValuesChange} | |||
| form={form} | |||
| node={node} | |||
| ></OperatorForm> | |||
| </FlowFormContext.Provider> | |||
| )} | |||
| </section> | |||
| {singleDebugDrawerVisible && ( | |||
| </SheetHeader> | |||
| <section className={styles.formWrapper}> | |||
| {visible && ( | |||
| <FlowFormContext.Provider value={node}> | |||
| <OperatorForm | |||
| onValuesChange={handleValuesChange} | |||
| form={form} | |||
| node={node} | |||
| ></OperatorForm> | |||
| </FlowFormContext.Provider> | |||
| )} | |||
| </section> | |||
| </SheetContent> | |||
| {/* {singleDebugDrawerVisible && ( | |||
| <SingleDebugDrawer | |||
| visible={singleDebugDrawerVisible} | |||
| hideModal={hideSingleDebugDrawer} | |||
| componentId={node?.id} | |||
| ></SingleDebugDrawer> | |||
| )} | |||
| </Drawer> | |||
| )} */} | |||
| </Sheet> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,151 @@ | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import { CloseOutlined } from '@ant-design/icons'; | |||
| import { Flex, 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 { useHandleFormValuesChange, useHandleNodeNameChange } from '../hooks'; | |||
| import OperatorIcon from '../operator-icon'; | |||
| import { | |||
| buildCategorizeListFromObject, | |||
| needsSingleStepDebugging, | |||
| } from '../utils'; | |||
| import SingleDebugDrawer from './single-debug-drawer'; | |||
| import { Sheet, SheetContent, SheetHeader } from '@/components/ui/sheet'; | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { FlowFormContext } from '../context'; | |||
| import { RunTooltip } from '../flow-tooltip'; | |||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||
| import { useForm } from 'react-hook-form'; | |||
| import { useFormConfigMap } from './use-form-config-map'; | |||
| interface IProps { | |||
| node?: RAGFlowNodeType; | |||
| singleDebugDrawerVisible: IModalProps<any>['visible']; | |||
| hideSingleDebugDrawer: IModalProps<any>['hideModal']; | |||
| showSingleDebugDrawer: IModalProps<any>['showModal']; | |||
| } | |||
| const EmptyContent = () => <div></div>; | |||
| const FormDrawer = ({ | |||
| visible, | |||
| hideModal, | |||
| node, | |||
| singleDebugDrawerVisible, | |||
| hideSingleDebugDrawer, | |||
| showSingleDebugDrawer, | |||
| }: IModalProps<any> & IProps) => { | |||
| const operatorName: Operator = node?.data.label as Operator; | |||
| const FormConfigMap = useFormConfigMap(); | |||
| const currentFormMap = FormConfigMap[operatorName]; | |||
| const OperatorForm = currentFormMap.component ?? EmptyContent; | |||
| const form = useForm({ | |||
| defaultValues: currentFormMap.defaultValues, | |||
| resolver: zodResolver(currentFormMap.schema), | |||
| }); | |||
| const { name, handleNameBlur, handleNameChange } = useHandleNodeNameChange({ | |||
| id: node?.id, | |||
| data: node?.data, | |||
| }); | |||
| const previousId = useRef<string | undefined>(node?.id); | |||
| const { t } = useTranslate('flow'); | |||
| const { handleValuesChange } = useHandleFormValuesChange(node?.id); | |||
| useEffect(() => { | |||
| if (visible) { | |||
| if (node?.id !== previousId.current) { | |||
| // form.resetFields(); | |||
| form.reset(); | |||
| form.clearErrors(); | |||
| } | |||
| 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 }); | |||
| form.reset({ ...formData, items }); | |||
| } | |||
| } else { | |||
| // form.setFieldsValue(node?.data?.form); | |||
| form.reset(node?.data?.form); | |||
| } | |||
| previousId.current = node?.id; | |||
| } | |||
| }, [visible, form, node?.data?.form, node?.id, node, operatorName]); | |||
| return ( | |||
| <Sheet onOpenChange={hideModal} open={visible}> | |||
| <SheetContent className="bg-white"> | |||
| <SheetHeader> | |||
| <Flex vertical> | |||
| <Flex gap={'middle'} align="center"> | |||
| <OperatorIcon | |||
| name={operatorName} | |||
| color={operatorMap[operatorName]?.color} | |||
| ></OperatorIcon> | |||
| <Flex align="center" gap={'small'} flex={1}> | |||
| <label htmlFor="">{t('title')}</label> | |||
| {node?.id === BeginId ? ( | |||
| <span>{t(BeginId)}</span> | |||
| ) : ( | |||
| <Input | |||
| value={name} | |||
| onBlur={handleNameBlur} | |||
| onChange={handleNameChange} | |||
| ></Input> | |||
| )} | |||
| </Flex> | |||
| {needsSingleStepDebugging(operatorName) && ( | |||
| <RunTooltip> | |||
| <Play | |||
| className="size-5 cursor-pointer" | |||
| onClick={showSingleDebugDrawer} | |||
| /> | |||
| </RunTooltip> | |||
| )} | |||
| <CloseOutlined onClick={hideModal} /> | |||
| </Flex> | |||
| <span>{t(`${lowerFirst(operatorName)}Description`)}</span> | |||
| </Flex> | |||
| </SheetHeader> | |||
| <section> | |||
| {visible && ( | |||
| <FlowFormContext.Provider value={node}> | |||
| <OperatorForm | |||
| onValuesChange={handleValuesChange} | |||
| form={form} | |||
| node={node} | |||
| ></OperatorForm> | |||
| </FlowFormContext.Provider> | |||
| )} | |||
| </section> | |||
| </SheetContent> | |||
| {singleDebugDrawerVisible && ( | |||
| <SingleDebugDrawer | |||
| visible={singleDebugDrawerVisible} | |||
| hideModal={hideSingleDebugDrawer} | |||
| componentId={node?.id} | |||
| ></SingleDebugDrawer> | |||
| )} | |||
| </Sheet> | |||
| ); | |||
| }; | |||
| export default FormDrawer; | |||
| @@ -0,0 +1,256 @@ | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { z } from 'zod'; | |||
| import { Operator } 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 IterationForm from '../form/iteration-from'; | |||
| 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'; | |||
| export function useFormConfigMap() { | |||
| const { t } = useTranslation(); | |||
| const FormConfigMap = { | |||
| [Operator.Begin]: { | |||
| component: BeginForm, | |||
| defaultValues: {}, | |||
| schema: z.object({ | |||
| name: z | |||
| .string() | |||
| .min(1, { | |||
| message: t('common.namePlaceholder'), | |||
| }) | |||
| .trim(), | |||
| age: z | |||
| .string() | |||
| .min(1, { | |||
| message: t('common.namePlaceholder'), | |||
| }) | |||
| .trim(), | |||
| }), | |||
| }, | |||
| [Operator.Retrieval]: { | |||
| component: RetrievalForm, | |||
| defaultValues: { query: [] }, | |||
| schema: z.object({ | |||
| name: z | |||
| .string() | |||
| .min(1, { | |||
| message: t('common.namePlaceholder'), | |||
| }) | |||
| .trim(), | |||
| age: z | |||
| .string() | |||
| .min(1, { | |||
| message: t('common.namePlaceholder'), | |||
| }) | |||
| .trim(), | |||
| query: z.array( | |||
| z.object({ | |||
| type: z.string(), | |||
| }), | |||
| ), | |||
| }), | |||
| }, | |||
| [Operator.Generate]: { | |||
| component: GenerateForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Answer]: { | |||
| component: AnswerForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Categorize]: { | |||
| component: CategorizeForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Message]: { | |||
| component: MessageForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Relevant]: { | |||
| component: RelevantForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.RewriteQuestion]: { | |||
| component: RewriteQuestionForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Baidu]: { | |||
| component: BaiduForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.DuckDuckGo]: { | |||
| component: DuckDuckGoForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.KeywordExtract]: { | |||
| component: KeywordExtractForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Wikipedia]: { | |||
| component: WikipediaForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.PubMed]: { | |||
| component: PubMedForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.ArXiv]: { | |||
| component: ArXivForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Google]: { | |||
| component: GoogleForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Bing]: { | |||
| component: BingForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.GoogleScholar]: { | |||
| component: GoogleScholarForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.DeepL]: { | |||
| component: DeepLForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.GitHub]: { | |||
| component: GithubForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.BaiduFanyi]: { | |||
| component: BaiduFanyiForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.QWeather]: { | |||
| component: QWeatherForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.ExeSQL]: { | |||
| component: ExeSQLForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Switch]: { | |||
| component: SwitchForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.WenCai]: { | |||
| component: WenCaiForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.AkShare]: { | |||
| component: AkShareForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.YahooFinance]: { | |||
| component: YahooFinanceForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Jin10]: { | |||
| component: Jin10Form, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.TuShare]: { | |||
| component: TuShareForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Crawler]: { | |||
| component: CrawlerForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Invoke]: { | |||
| component: InvokeForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Concentrator]: { | |||
| component: () => <></>, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Note]: { | |||
| component: () => <></>, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Template]: { | |||
| component: TemplateForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Email]: { | |||
| component: EmailForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.Iteration]: { | |||
| component: IterationForm, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| [Operator.IterationStart]: { | |||
| component: () => <></>, | |||
| defaultValues: {}, | |||
| schema: z.object({}), | |||
| }, | |||
| }; | |||
| return FormConfigMap; | |||
| } | |||
| @@ -0,0 +1,109 @@ | |||
| 'use client'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| FormControl, | |||
| FormDescription, | |||
| FormField, | |||
| FormItem, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { Input } from '@/components/ui/input'; | |||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { CircleMinus, Plus } from 'lucide-react'; | |||
| import { useFieldArray, useFormContext } from 'react-hook-form'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { useBuildComponentIdSelectOptions } from '../../hooks/use-get-begin-query'; | |||
| interface IProps { | |||
| node?: RAGFlowNodeType; | |||
| } | |||
| enum VariableType { | |||
| Reference = 'reference', | |||
| Input = 'input', | |||
| } | |||
| const getVariableName = (type: string) => | |||
| type === VariableType.Reference ? 'component_id' : 'value'; | |||
| export function DynamicVariableForm({ node }: IProps) { | |||
| const { t } = useTranslation(); | |||
| const form = useFormContext(); | |||
| const { fields, remove, append } = useFieldArray({ | |||
| name: 'query', | |||
| control: form.control, | |||
| }); | |||
| const valueOptions = useBuildComponentIdSelectOptions( | |||
| node?.id, | |||
| node?.parentId, | |||
| ); | |||
| const options = [ | |||
| { value: VariableType.Reference, label: t('flow.reference') }, | |||
| { value: VariableType.Input, label: t('flow.text') }, | |||
| ]; | |||
| return ( | |||
| <div> | |||
| {fields.map((field, index) => { | |||
| const typeField = `query.${index}.type`; | |||
| const typeValue = form.watch(typeField); | |||
| return ( | |||
| <div key={field.id} className="flex items-center gap-1"> | |||
| <FormField | |||
| control={form.control} | |||
| name={typeField} | |||
| render={({ field }) => ( | |||
| <FormItem className="w-2/5"> | |||
| {/* <FormLabel>City</FormLabel> */} | |||
| <FormDescription /> | |||
| <FormControl> | |||
| <RAGFlowSelect | |||
| // placeholder={t('common.pleaseSelect')} | |||
| {...field} | |||
| options={options} | |||
| ></RAGFlowSelect> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| <FormField | |||
| control={form.control} | |||
| name={`query.${index}.${getVariableName(typeValue)}`} | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| {/* <FormLabel>State</FormLabel> */} | |||
| <FormDescription /> | |||
| <FormControl> | |||
| {typeValue === VariableType.Reference ? ( | |||
| <RAGFlowSelect | |||
| // placeholder={t('common.pleaseSelect')} | |||
| {...field} | |||
| options={valueOptions} | |||
| ></RAGFlowSelect> | |||
| ) : ( | |||
| <Input placeholder={t('common.pleaseInput')} {...field} /> | |||
| )} | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| <CircleMinus | |||
| className="cursor-pointer" | |||
| onClick={() => remove(index)} | |||
| /> | |||
| </div> | |||
| ); | |||
| })} | |||
| <Button onClick={append} className="w-full mt-4"> | |||
| <Plus /> | |||
| {t('flow.addVariable')} | |||
| </Button> | |||
| </div> | |||
| ); | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| import { KnowledgeBaseFormField } from '@/components/knowledge-base-item'; | |||
| import { RerankFormFields } from '@/components/rerank'; | |||
| import { SimilaritySliderFormField } from '@/components/similarity-slider'; | |||
| import { TopNFormField } from '@/components/top-n-item'; | |||
| import { | |||
| Form, | |||
| FormControl, | |||
| FormField, | |||
| FormItem, | |||
| FormLabel, | |||
| FormMessage, | |||
| } from '@/components/ui/form'; | |||
| import { Textarea } from '@/components/ui/textarea'; | |||
| import { useTranslate } from '@/hooks/common-hooks'; | |||
| import { INextOperatorForm } from '../../interface'; | |||
| import { DynamicVariableForm } from '../components/next-dynamic-input-variable'; | |||
| const RetrievalForm = ({ form, node }: INextOperatorForm) => { | |||
| const { t } = useTranslate('flow'); | |||
| return ( | |||
| <Form {...form}> | |||
| <DynamicVariableForm></DynamicVariableForm> | |||
| <SimilaritySliderFormField name="keywords_similarity_weight"></SimilaritySliderFormField> | |||
| <TopNFormField></TopNFormField> | |||
| <RerankFormFields></RerankFormFields> | |||
| <KnowledgeBaseFormField></KnowledgeBaseFormField> | |||
| <FormField | |||
| control={form.control} | |||
| name="empty_response" | |||
| render={({ field }) => ( | |||
| <FormItem> | |||
| <FormLabel>{t('chat.emptyResponse')}</FormLabel> | |||
| <FormControl> | |||
| <Textarea | |||
| placeholder={t('common.namePlaceholder')} | |||
| {...field} | |||
| autoComplete="off" | |||
| rows={4} | |||
| /> | |||
| </FormControl> | |||
| <FormMessage /> | |||
| </FormItem> | |||
| )} | |||
| /> | |||
| </Form> | |||
| ); | |||
| }; | |||
| export default RetrievalForm; | |||
| @@ -1,5 +1,6 @@ | |||
| import { RAGFlowNodeType } from '@/interfaces/database/flow'; | |||
| import { FormInstance } from 'antd'; | |||
| import { UseFormReturn } from 'react-hook-form'; | |||
| export interface IOperatorForm { | |||
| onValuesChange?(changedValues: any, values: any): void; | |||
| @@ -8,6 +9,12 @@ export interface IOperatorForm { | |||
| nodeId?: string; | |||
| } | |||
| export interface INextOperatorForm { | |||
| form: UseFormReturn; | |||
| node?: RAGFlowNodeType; | |||
| nodeId?: string; | |||
| } | |||
| export interface IGenerateParameter { | |||
| id?: string; | |||
| key: string; | |||