diff --git a/web/src/components/edit-tag/index.tsx b/web/src/components/edit-tag/index.tsx index ccf10b8ef..decfbb968 100644 --- a/web/src/components/edit-tag/index.tsx +++ b/web/src/components/edit-tag/index.tsx @@ -16,7 +16,7 @@ interface EditTagsProps { } const EditTag = React.forwardRef( - ({ value = [], onChange, disabled }: EditTagsProps) => { + function EditTag({ value = [], onChange, disabled }, ref) { const [inputVisible, setInputVisible] = useState(false); const [inputValue, setInputValue] = useState(''); const inputRef = useRef(null); @@ -82,7 +82,7 @@ const EditTag = React.forwardRef( const tagChild = value?.map(forMap); return ( -
+
{inputVisible && ( = ({ - className, - value: initialValue, - onChange, - height, - min = 0, - max = Infinity, -}) => { - const [value, setValue] = useState(() => { - return initialValue ?? 0; - }); +const NumberInput = forwardRef( + function NumberInput( + { + className, + value: initialValue, + onChange, + height, + min = 0, + max = Infinity, + }, + ref, + ) { + const [value, setValue] = useState(() => { + return initialValue ?? 0; + }); - const valueRef = useRef(); + const valueRef = useRef(); - useEffect(() => { - if (initialValue !== undefined) { - setValue(initialValue); - } - }, [initialValue]); - - const handleDecrement = () => { - if (isNumber(value) && value > min) { - setValue(value - 1); - onChange?.(value - 1); - } - }; - - const handleIncrement = () => { - if (!isNumber(value)) { - return; - } - if (value > max - 1) { - return; - } - setValue(value + 1); - onChange?.(value + 1); - }; - - const handleChange = (e: React.ChangeEvent) => { - const currentValue = e.target.value; - const newValue = Number(currentValue); - - if (trim(currentValue) === '') { - if (isNumber(value)) { - valueRef.current = value; + useEffect(() => { + if (initialValue !== undefined) { + setValue(initialValue); } - setValue(''); - return; - } + }, [initialValue]); - if (!isNaN(newValue)) { - if (newValue > max || newValue < min) { + const handleDecrement = () => { + if (isNumber(value) && value > min) { + setValue(value - 1); + onChange?.(value - 1); + } + }; + + const handleIncrement = () => { + if (!isNumber(value)) { return; } - setValue(newValue); - onChange?.(newValue); - } - }; + if (value > max - 1) { + return; + } + setValue(value + 1); + onChange?.(value + 1); + }; - const handleBlur: FocusEventHandler = useCallback(() => { - if (isNumber(value)) { - onChange?.(value); - } else { - const previousValue = valueRef.current ?? min; - setValue(previousValue); - onChange?.(previousValue); - } - }, [min, onChange, value]); + const handleChange = (e: React.ChangeEvent) => { + const currentValue = e.target.value; + const newValue = Number(currentValue); - const style = useMemo( - () => ({ - height: height ? `${height.toString().replace('px', '')}px` : 'auto', - }), - [height], - ); - return ( -
- - - -
- ); -}; + + + +
+ ); + }, +); export default NumberInput; diff --git a/web/src/pages/agent/flow-tooltip.tsx b/web/src/pages/agent/flow-tooltip.tsx index 9386dd06b..801b675b5 100644 --- a/web/src/pages/agent/flow-tooltip.tsx +++ b/web/src/pages/agent/flow-tooltip.tsx @@ -10,7 +10,7 @@ export const RunTooltip = ({ children }: PropsWithChildren) => { const { t } = useTranslation(); return ( - {children} + {children}

{t('flow.testRun')}

diff --git a/web/src/pages/agent/form-sheet/form-config-map.tsx b/web/src/pages/agent/form-sheet/form-config-map.tsx index a552412f1..5ff04ce28 100644 --- a/web/src/pages/agent/form-sheet/form-config-map.tsx +++ b/web/src/pages/agent/form-sheet/form-config-map.tsx @@ -181,4 +181,10 @@ export const FormConfigMap = { [Operator.ExitLoop]: { component: () => <>, }, + [Operator.LoopStart]: { + component: () => <>, + }, + [Operator.ExcelProcessor]: { + component: () => <>, + }, }; diff --git a/web/src/pages/agent/form/categorize-form/dynamic-categorize.tsx b/web/src/pages/agent/form/categorize-form/dynamic-categorize.tsx index 0807f7bfa..582cb57ff 100644 --- a/web/src/pages/agent/form/categorize-form/dynamic-categorize.tsx +++ b/web/src/pages/agent/form/categorize-form/dynamic-categorize.tsx @@ -11,17 +11,19 @@ import { FormLabel, FormMessage, } from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; +import { Input, InputProps } from '@/components/ui/input'; +import { Separator } from '@/components/ui/separator'; import { BlurTextarea } from '@/components/ui/textarea'; import { useTranslate } from '@/hooks/common-hooks'; import { PlusOutlined } from '@ant-design/icons'; import { useUpdateNodeInternals } from '@xyflow/react'; import humanId from 'human-id'; import trim from 'lodash/trim'; -import { ChevronsUpDown, X } from 'lucide-react'; +import { ChevronsUpDown, Trash2 } from 'lucide-react'; import { ChangeEventHandler, FocusEventHandler, + forwardRef, memo, useCallback, useEffect, @@ -32,7 +34,7 @@ import { v4 as uuid } from 'uuid'; import { z } from 'zod'; import useGraphStore from '../../store'; import DynamicExample from './dynamic-example'; -import { useCreateCategorizeFormSchema } from './use-form-schema'; +import { CreateCategorizeFormSchema } from './use-form-schema'; interface IProps { nodeId?: string; @@ -58,12 +60,10 @@ const getOtherFieldValues = ( x !== form.getValues(`${formListName}.${index}.${latestField}`), ); -const InnerNameInput = ({ - value, - onChange, - otherNames, - validate, -}: INameInputProps) => { +const InnerNameInput = forwardRef< + HTMLInputElement, + InputProps & INameInputProps +>(function InnerNameInput({ value, onChange, otherNames, validate }, ref) { const [name, setName] = useState(); const { t } = useTranslate('flow'); @@ -103,9 +103,10 @@ const InnerNameInput = ({ value={name} onChange={handleNameChange} onBlur={handleNameBlur} + ref={ref} > ); -}; +}); const NameInput = memo(InnerNameInput); @@ -127,7 +128,6 @@ const InnerFormSet = ({ index }: IProps & { index: number }) => { name={buildFieldName('name')} render={({ field }) => ( - {t('categoryName')} { const updateNodeInternals = useUpdateNodeInternals(); - const FormSchema = useCreateCategorizeFormSchema(); const deleteCategorizeCaseEdges = useGraphStore( (state) => state.deleteEdgesBySourceAndSourceHandle, ); - const form = useFormContext>(); + const form = useFormContext>(); const { t } = useTranslate('flow'); const { fields, remove, append } = useFieldArray({ name: 'items', @@ -208,41 +207,42 @@ const DynamicCategorize = ({ nodeId }: IProps) => { ); return ( -
+
{fields.map((field, index) => ( - -
-

- {form.getValues(`items.${index}.name`)} -

- -
- - -
-
-
- - - -
+
+ +
+ {form.getValues(`items.${index}.name`)} + +
+ + +
+
+
+ + + +
+ +
))} -
+ ); }; diff --git a/web/src/pages/agent/form/categorize-form/dynamic-example.tsx b/web/src/pages/agent/form/categorize-form/dynamic-example.tsx index 35d95cbc6..c8c0e99cc 100644 --- a/web/src/pages/agent/form/categorize-form/dynamic-example.tsx +++ b/web/src/pages/agent/form/categorize-form/dynamic-example.tsx @@ -1,3 +1,4 @@ +import { Collapse } from '@/components/collapse'; import { Button } from '@/components/ui/button'; import { FormControl, @@ -7,7 +8,7 @@ import { FormMessage, } from '@/components/ui/form'; import { Textarea } from '@/components/ui/textarea'; -import { Plus, X } from 'lucide-react'; +import { Plus, Trash2 } from 'lucide-react'; import { memo } from 'react'; import { useFieldArray, useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; @@ -24,44 +25,49 @@ const DynamicExample = ({ name }: DynamicExampleProps) => { }); return ( - - {t('flow.examples')} -
- {fields.map((field, index) => ( -
- ( - - - - - + {t('flow.examples')} + } + > + +
+ {fields.map((field, index) => ( +
+ ( + + + + + + )} + /> + {index === 0 ? ( + + ) : ( + )} - /> - {index === 0 ? ( - - ) : ( - - )} -
- ))} -
- -
+
+ ))} +
+ +
+ ); }; diff --git a/web/src/pages/agent/form/categorize-form/index.tsx b/web/src/pages/agent/form/categorize-form/index.tsx index f0e38a733..de6983006 100644 --- a/web/src/pages/agent/form/categorize-form/index.tsx +++ b/web/src/pages/agent/form/categorize-form/index.tsx @@ -1,7 +1,7 @@ -import { FormContainer } from '@/components/form-container'; import { LargeModelFormField } from '@/components/large-model-form-field'; import { MessageHistoryWindowSizeFormField } from '@/components/message-history-window-size-item'; import { Form } from '@/components/ui/form'; +import { Separator } from '@/components/ui/separator'; import { zodResolver } from '@hookform/resolvers/zod'; import { memo } from 'react'; import { useForm } from 'react-hook-form'; @@ -33,13 +33,12 @@ function CategorizeForm({ node }: INextOperatorForm) { return (
- - - - + + + diff --git a/web/src/pages/agent/form/categorize-form/use-form-schema.ts b/web/src/pages/agent/form/categorize-form/use-form-schema.ts index 9e56bb18b..6ff507ee8 100644 --- a/web/src/pages/agent/form/categorize-form/use-form-schema.ts +++ b/web/src/pages/agent/form/categorize-form/use-form-schema.ts @@ -30,3 +30,7 @@ export function useCreateCategorizeFormSchema() { return FormSchema; } + +export type CreateCategorizeFormSchema = ReturnType< + typeof useCreateCategorizeFormSchema +>; diff --git a/web/src/pages/agent/form/variable-aggregator-form/name-input.tsx b/web/src/pages/agent/form/variable-aggregator-form/name-input.tsx index 5a0f14ba8..4ed895e14 100644 --- a/web/src/pages/agent/form/variable-aggregator-form/name-input.tsx +++ b/web/src/pages/agent/form/variable-aggregator-form/name-input.tsx @@ -1,6 +1,6 @@ -import { Input } from '@/components/ui/input'; +import { Input, InputProps } from '@/components/ui/input'; import { PenLine } from 'lucide-react'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { forwardRef, useCallback, useEffect, useRef, useState } from 'react'; import { useHandleNameChange } from './use-handle-name-change'; type NameInputProps = { @@ -8,7 +8,10 @@ type NameInputProps = { onChange: (value: string) => void; }; -export function NameInput({ value, onChange }: NameInputProps) { +export const NameInput = forwardRef< + HTMLInputElement, + InputProps & NameInputProps +>(function NameInput({ value, onChange }, ref) { const { name, handleNameBlur, handleNameChange } = useHandleNameChange(value); const inputRef = useRef(null); @@ -33,7 +36,7 @@ export function NameInput({ value, onChange }: NameInputProps) { }, [isEditingMode]); return ( -
+
{isEditingMode ? ( ); -} +});