### What problem does this PR solve? Feat: Use react-hook-form to synchronize the data of the categorize form to the agent node. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.17.1
| @@ -65,12 +65,15 @@ const FormSheet = ({ | |||
| const { t } = useTranslate('flow'); | |||
| const { handleValuesChange } = useHandleFormValuesChange(node?.id); | |||
| const { handleValuesChange } = useHandleFormValuesChange( | |||
| operatorName, | |||
| node?.id, | |||
| form, | |||
| ); | |||
| useEffect(() => { | |||
| if (visible) { | |||
| if (visible && !form.formState.isDirty) { | |||
| if (node?.id !== previousId.current) { | |||
| // form.resetFields(); | |||
| form.reset(); | |||
| form.clearErrors(); | |||
| } | |||
| @@ -1,45 +0,0 @@ | |||
| import { | |||
| ICategorizeItem, | |||
| ICategorizeItemResult, | |||
| } from '@/interfaces/database/flow'; | |||
| import omit from 'lodash/omit'; | |||
| import { useCallback } from 'react'; | |||
| import { IOperatorForm } from '../../interface'; | |||
| /** | |||
| * Convert the list in the following form into an object | |||
| * { | |||
| "items": [ | |||
| { | |||
| "name": "Categorize 1", | |||
| "description": "111", | |||
| "examples": "ddd", | |||
| "to": "Retrieval:LazyEelsStick" | |||
| } | |||
| ] | |||
| } | |||
| */ | |||
| const buildCategorizeObjectFromList = (list: Array<ICategorizeItem>) => { | |||
| return list.reduce<ICategorizeItemResult>((pre, cur) => { | |||
| if (cur?.name) { | |||
| pre[cur.name] = omit(cur, 'name'); | |||
| } | |||
| return pre; | |||
| }, {}); | |||
| }; | |||
| export const useHandleFormValuesChange = ({ | |||
| onValuesChange, | |||
| }: IOperatorForm) => { | |||
| const handleValuesChange = useCallback( | |||
| (changedValues: any, values: any) => { | |||
| onValuesChange?.(changedValues, { | |||
| ...omit(values, 'items'), | |||
| category_description: buildCategorizeObjectFromList(values.items), | |||
| }); | |||
| }, | |||
| [onValuesChange], | |||
| ); | |||
| return { handleValuesChange }; | |||
| }; | |||
| @@ -6,17 +6,8 @@ import { DynamicInputVariable } from '../components/next-dynamic-input-variable' | |||
| import DynamicCategorize from './dynamic-categorize'; | |||
| const CategorizeForm = ({ form, node }: INextOperatorForm) => { | |||
| // const { handleValuesChange } = useHandleFormValuesChange({ | |||
| // form, | |||
| // nodeId: node?.id, | |||
| // onValuesChange, | |||
| // }); | |||
| return ( | |||
| <Form | |||
| // onValuesChange={handleValuesChange} | |||
| {...form} | |||
| > | |||
| <Form {...form}> | |||
| <form | |||
| className="space-y-6 p-5 overflow-auto max-h-[76vh]" | |||
| onSubmit={(e) => { | |||
| @@ -23,8 +23,9 @@ import { | |||
| } from '@/interfaces/database/flow'; | |||
| import { message } from 'antd'; | |||
| import { humanId } from 'human-id'; | |||
| import { get, lowerFirst } from 'lodash'; | |||
| import { get, lowerFirst, omit } from 'lodash'; | |||
| import trim from 'lodash/trim'; | |||
| import { UseFormReturn } from 'react-hook-form'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { v4 as uuid } from 'uuid'; | |||
| import { | |||
| @@ -69,6 +70,7 @@ import { | |||
| } from './constant'; | |||
| import useGraphStore, { RFState } from './store'; | |||
| import { | |||
| buildCategorizeObjectFromList, | |||
| generateNodeNamesWithIncreasingIndex, | |||
| generateSwitchHandleText, | |||
| getNodeDragHandle, | |||
| @@ -258,7 +260,11 @@ export const useHandleDrop = () => { | |||
| return { onDrop, onDragOver, setReactFlowInstance }; | |||
| }; | |||
| export const useHandleFormValuesChange = (id?: string) => { | |||
| export const useHandleFormValuesChange = ( | |||
| operatorName: Operator, | |||
| id?: string, | |||
| form?: UseFormReturn, | |||
| ) => { | |||
| const updateNodeForm = useGraphStore((state) => state.updateNodeForm); | |||
| const handleValuesChange = useCallback( | |||
| (changedValues: any, values: any) => { | |||
| @@ -283,6 +289,41 @@ export const useHandleFormValuesChange = (id?: string) => { | |||
| [updateNodeForm, id], | |||
| ); | |||
| useEffect(() => { | |||
| const subscription = form?.watch((value, { name, type, values }) => { | |||
| if (id && name) { | |||
| console.log('🚀 ~ useEffect ~ value:', type, values); | |||
| let nextValues: any = value; | |||
| // Fixed the issue that the related form value does not change after selecting the freedom field of the model | |||
| if ( | |||
| name === 'parameter' && | |||
| value['parameter'] in settledModelVariableMap | |||
| ) { | |||
| nextValues = { | |||
| ...value, | |||
| ...settledModelVariableMap[ | |||
| value['parameter'] as keyof typeof settledModelVariableMap | |||
| ], | |||
| }; | |||
| } | |||
| const categoryDescriptionRegex = /items\.\d+\.name/g; | |||
| if ( | |||
| operatorName === Operator.Categorize && | |||
| categoryDescriptionRegex.test(name) | |||
| ) { | |||
| nextValues = { | |||
| ...omit(value, 'items'), | |||
| category_description: buildCategorizeObjectFromList(value.items), | |||
| }; | |||
| } | |||
| updateNodeForm(id, nextValues); | |||
| } | |||
| }); | |||
| return () => subscription?.unsubscribe(); | |||
| }, [form, form?.watch, id, operatorName, updateNodeForm]); | |||
| return { handleValuesChange }; | |||
| }; | |||
| @@ -8,7 +8,7 @@ import { removeUselessFieldsFromValues } from '@/utils/form'; | |||
| import { Edge, Node, Position, XYPosition } from '@xyflow/react'; | |||
| import { FormInstance, FormListFieldData } from 'antd'; | |||
| import { humanId } from 'human-id'; | |||
| import { curry, get, intersectionWith, isEqual, sample } from 'lodash'; | |||
| import { curry, get, intersectionWith, isEqual, omit, sample } from 'lodash'; | |||
| import pipe from 'lodash/fp/pipe'; | |||
| import isObject from 'lodash/isObject'; | |||
| import { v4 as uuidv4 } from 'uuid'; | |||
| @@ -416,3 +416,25 @@ export const buildCategorizeListFromObject = ( | |||
| }, []) | |||
| .sort((a, b) => a.index - b.index); | |||
| }; | |||
| /** | |||
| * Convert the list in the following form into an object | |||
| * { | |||
| "items": [ | |||
| { | |||
| "name": "Categorize 1", | |||
| "description": "111", | |||
| "examples": "ddd", | |||
| "to": "Retrieval:LazyEelsStick" | |||
| } | |||
| ] | |||
| } | |||
| */ | |||
| export const buildCategorizeObjectFromList = (list: Array<ICategorizeItem>) => { | |||
| return list.reduce<ICategorizeItemResult>((pre, cur) => { | |||
| if (cur?.name) { | |||
| pre[cur.name] = omit(cur, 'name'); | |||
| } | |||
| return pre; | |||
| }, {}); | |||
| }; | |||