Files
ragflow/web/src/pages/agent/form-sheet/next.tsx
balibabu e97fd2b5e6 Feat: Add InnerBlurInput component to avoid frequent updates of zustand causing the input box to lose focus #3221 (#7955)
### What problem does this PR solve?

Feat: Add InnerBlurInput component to avoid frequent updates of zustand
causing the input box to lose focus #3221
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
2025-05-29 19:52:56 +08:00

176 lines
5.4 KiB
TypeScript

import { Input } from '@/components/ui/input';
import {
Sheet,
SheetContent,
SheetHeader,
SheetTitle,
} from '@/components/ui/sheet';
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 omit from 'lodash/omit';
import { Play, X } from 'lucide-react';
import { useEffect, useRef } from 'react';
import { useForm } from 'react-hook-form';
import { BeginId, Operator, operatorMap } from '../constant';
import { FlowFormContext } from '../context';
import { RunTooltip } from '../flow-tooltip';
import { useHandleNodeNameChange } from '../hooks';
import { useHandleFormValuesChange } from '../hooks/use-watch-form-change';
import OperatorIcon from '../operator-icon';
import {
buildCategorizeListFromObject,
convertToObjectArray,
needsSingleStepDebugging,
} from '../utils';
import SingleDebugDrawer from './single-debug-drawer';
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 FormSheet = ({
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({
values: 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(
operatorName,
node?.id,
form,
);
useEffect(() => {
if (visible) {
if (node?.id !== previousId.current) {
form.reset();
form.clearErrors();
}
const formData = node?.data?.form;
if (operatorName === Operator.Categorize) {
const items = buildCategorizeListFromObject(
get(node, 'data.form.category_description', {}),
);
if (isPlainObject(formData)) {
// form.setFieldsValue({ ...formData, items });
console.info('xxx');
const nextValues = {
...omit(formData, 'category_description'),
items,
};
// Object.entries(nextValues).forEach(([key, value]) => {
// form.setValue(key, value, { shouldDirty: false });
// });
form.reset(nextValues);
}
} else if (operatorName === Operator.Message) {
form.reset({
...formData,
content: convertToObjectArray(formData.content),
});
} 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 open={visible} modal={false}>
<SheetTitle className="hidden"></SheetTitle>
<SheetContent className={cn('top-20 p-0')} closeIcon={false}>
<SheetHeader>
<section className="flex-col border-b py-2 px-5">
<div className="flex items-center gap-2 pb-3">
<OperatorIcon
name={operatorName}
color={operatorMap[operatorName]?.color}
></OperatorIcon>
<div className="flex items-center gap-1 flex-1">
<label htmlFor="">{t('title')}</label>
{node?.id === BeginId ? (
<span>{t(BeginId)}</span>
) : (
<Input
value={name}
onBlur={handleNameBlur}
onChange={handleNameChange}
></Input>
)}
</div>
{needsSingleStepDebugging(operatorName) && (
<RunTooltip>
<Play
className="size-5 cursor-pointer"
onClick={showSingleDebugDrawer}
/>
</RunTooltip>
)}
<X onClick={hideModal} />
</div>
<span>{t(`${lowerFirst(operatorName)}Description`)}</span>
</section>
</SheetHeader>
<section className="pt-4 overflow-auto max-h-[85vh]">
{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 FormSheet;