diff --git a/web/src/components/confirm-delete-dialog.tsx b/web/src/components/confirm-delete-dialog.tsx index 412445658..0bd36a194 100644 --- a/web/src/components/confirm-delete-dialog.tsx +++ b/web/src/components/confirm-delete-dialog.tsx @@ -8,7 +8,7 @@ import { AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'; -import { PropsWithChildren } from 'react'; +import { DialogProps } from '@radix-ui/react-dialog'; import { useTranslation } from 'react-i18next'; interface IProps { @@ -24,7 +24,10 @@ export function ConfirmDeleteDialog({ onOk, onCancel, hidden = false, -}: IProps & PropsWithChildren) { + onOpenChange, + open, + defaultOpen, +}: IProps & DialogProps) { const { t } = useTranslation(); if (hidden) { @@ -32,7 +35,11 @@ export function ConfirmDeleteDialog({ } return ( - + {children} e.preventDefault()} diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index a46122da7..4e9686fb1 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1765,6 +1765,9 @@ Important structured information may include: names, dates, locations, events, k metadata: `Content: [INSERT CONTENT HERE]`, }, }, + cancel: 'Cancel', + swicthPromptMessage: + 'The prompt word will change. Please confirm whether to abandon the existing prompt word?', }, }, }; diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index a11fbbc0b..030e27ee2 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1683,6 +1683,8 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 metadata: `内容:[在此处插入内容]`, }, }, + cancel: '取消', + switchPromptMessage: '提示词将发生变化,请确认是否放弃已有提示词?', }, }, }; diff --git a/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx b/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx index a97868bdd..cb4905b45 100644 --- a/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx +++ b/web/src/pages/agent/form/components/prompt-editor/variable-picker-plugin.tsx @@ -10,7 +10,6 @@ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext import { LexicalTypeaheadMenuPlugin, MenuOption, - useBasicTypeaheadTriggerMatch, } from '@lexical/react/LexicalTypeaheadMenuPlugin'; import { $createParagraphNode, @@ -131,9 +130,23 @@ export default function VariablePickerMenuPlugin({ baseOptions, }: VariablePickerMenuPluginProps): JSX.Element { const [editor] = useLexicalComposerContext(); - const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', { - minLength: 0, - }); + + // const checkForTriggerMatch = useBasicTypeaheadTriggerMatch('/', { + // minLength: 0, + // }); + + const testTriggerFn = React.useCallback((text: string) => { + const lastChar = text.slice(-1); + if (lastChar === '/') { + console.log('Found trigger character "/"'); + return { + leadOffset: text.length - 1, + matchingString: '', + replaceableString: '/', + }; + } + return null; + }, []); const previousValue = useRef(); @@ -291,6 +304,21 @@ export default function VariablePickerMenuPlugin({ } }, [parseTextToVariableNodes, editor, value]); + // Fixed the issue where the cursor would go to the end when changing its own data + useEffect(() => { + return editor.registerUpdateListener(({ editorState, tags }) => { + // If we trigger the programmatic update ourselves, we should not write back to avoid an infinite loop. + if (tags.has(ProgrammaticTag)) return; + + editorState.read(() => { + const text = $getRoot().getTextContent(); + if (text !== previousValue.current) { + previousValue.current = text; + } + }); + }); + }, [editor]); + return ( onQueryChange={setQueryString} @@ -301,7 +329,7 @@ export default function VariablePickerMenuPlugin({ closeMenu, ) } - triggerFn={checkForTriggerMatch} + triggerFn={testTriggerFn} options={buildNextOptions()} menuRenderFn={(anchorElementRef, { selectOptionAndCleanUp }) => { const nextOptions = buildNextOptions(); diff --git a/web/src/pages/data-flow/form/extractor-form/index.tsx b/web/src/pages/data-flow/form/extractor-form/index.tsx index 8021818b8..cb0abc877 100644 --- a/web/src/pages/data-flow/form/extractor-form/index.tsx +++ b/web/src/pages/data-flow/form/extractor-form/index.tsx @@ -1,3 +1,4 @@ +import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; import { LargeModelFormField } from '@/components/large-model-form-field'; import { LlmSettingSchema } from '@/components/llm-setting-items/next'; import { SelectWithSearch } from '@/components/originui/select-with-search'; @@ -6,7 +7,7 @@ import { Form } from '@/components/ui/form'; import { PromptEditor } from '@/pages/agent/form/components/prompt-editor'; import { buildOptions } from '@/utils/form'; import { zodResolver } from '@hookform/resolvers/zod'; -import { memo, useCallback } from 'react'; +import { memo } from 'react'; import { useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { z } from 'zod'; @@ -19,6 +20,7 @@ import { useFormValues } from '../../hooks/use-form-values'; import { useWatchFormChange } from '../../hooks/use-watch-form-change'; import { INextOperatorForm } from '../../interface'; import { FormWrapper } from '../components/form-wrapper'; +import { useSwitchPrompt } from './use-switch-prompt'; export const FormSchema = z.object({ field_name: z.string(), @@ -43,25 +45,13 @@ const ExtractorForm = ({ node }: INextOperatorForm) => { const options = buildOptions(ContextGeneratorFieldName, t, 'dataflow'); - const setPromptValue = useCallback( - (field: keyof ExtractorFormSchemaType, key: string, value: string) => { - form.setValue(field, t(`dataflow.prompts.${key}.${value}`), { - shouldDirty: true, - shouldValidate: true, - }); - }, - [form, t], - ); - - const handleFieldNameChange = useCallback( - (value: string) => { - if (value) { - setPromptValue('sys_prompt', 'system', value); - setPromptValue('prompts', 'user', value); - } - }, - [setPromptValue], - ); + const { + handleFieldNameChange, + confirmSwitch, + hideModal, + visible, + cancelSwitch, + } = useSwitchPrompt(form); useWatchFormChange(node?.id, form); @@ -96,6 +86,15 @@ const ExtractorForm = ({ node }: INextOperatorForm) => { > + {visible && ( + + )} ); }; diff --git a/web/src/pages/data-flow/form/extractor-form/use-switch-prompt.ts b/web/src/pages/data-flow/form/extractor-form/use-switch-prompt.ts new file mode 100644 index 000000000..4efb2c472 --- /dev/null +++ b/web/src/pages/data-flow/form/extractor-form/use-switch-prompt.ts @@ -0,0 +1,69 @@ +import { LlmSettingSchema } from '@/components/llm-setting-items/next'; +import { useSetModalState } from '@/hooks/common-hooks'; +import { useCallback, useRef } from 'react'; +import { UseFormReturn } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { z } from 'zod'; + +export const FormSchema = z.object({ + field_name: z.string(), + sys_prompt: z.string(), + prompts: z.string().optional(), + ...LlmSettingSchema, +}); + +export type ExtractorFormSchemaType = z.infer; + +export function useSwitchPrompt(form: UseFormReturn) { + const { visible, showModal, hideModal } = useSetModalState(); + const { t } = useTranslation(); + const previousFieldNames = useRef([form.getValues('field_name')]); + + const setPromptValue = useCallback( + (field: keyof ExtractorFormSchemaType, key: string, value: string) => { + form.setValue(field, t(`dataflow.prompts.${key}.${value}`), { + shouldDirty: true, + shouldValidate: true, + }); + }, + [form, t], + ); + + const handleFieldNameChange = useCallback( + (value: string) => { + if (value) { + const names = previousFieldNames.current; + if (names.length > 1) { + names.shift(); + } + names.push(value); + showModal(); + } + }, + [showModal], + ); + + const confirmSwitch = useCallback(() => { + const value = form.getValues('field_name'); + setPromptValue('sys_prompt', 'system', value); + setPromptValue('prompts', 'user', value); + }, [form, setPromptValue]); + + const cancelSwitch = useCallback(() => { + const previousValue = previousFieldNames.current.at(-2); + if (previousValue) { + form.setValue('field_name', previousValue, { + shouldDirty: true, + shouldValidate: true, + }); + } + }, [form]); + + return { + handleFieldNameChange, + confirmSwitch, + hideModal, + visible, + cancelSwitch, + }; +} diff --git a/web/src/pages/data-flow/hooks/use-cancel-dataflow.ts b/web/src/pages/data-flow/hooks/use-cancel-dataflow.ts index 1099660e5..a81176909 100644 --- a/web/src/pages/data-flow/hooks/use-cancel-dataflow.ts +++ b/web/src/pages/data-flow/hooks/use-cancel-dataflow.ts @@ -4,11 +4,9 @@ import { useCallback } from 'react'; export function useCancelCurrentDataflow({ messageId, setMessageId, - hideLogSheet, }: { messageId: string; setMessageId: (messageId: string) => void; - hideLogSheet(): void; }) { const { cancelDataflow } = useCancelDataflow(); @@ -16,9 +14,8 @@ export function useCancelCurrentDataflow({ const code = await cancelDataflow(messageId); if (code === 0) { setMessageId(''); - hideLogSheet(); } - }, [cancelDataflow, hideLogSheet, messageId, setMessageId]); + }, [cancelDataflow, messageId, setMessageId]); return { handleCancel }; } diff --git a/web/src/pages/data-flow/hooks/use-watch-form-change.ts b/web/src/pages/data-flow/hooks/use-watch-form-change.ts index 8c23dfb7f..1f85b107f 100644 --- a/web/src/pages/data-flow/hooks/use-watch-form-change.ts +++ b/web/src/pages/data-flow/hooks/use-watch-form-change.ts @@ -4,10 +4,6 @@ import useGraphStore from '../store'; export function useWatchFormChange(id?: string, form?: UseFormReturn) { let values = useWatch({ control: form?.control }); - console.log( - '🚀 ~ useWatchFormChange ~ values:', - JSON.stringify(values, null, 2), - ); const updateNodeForm = useGraphStore((state) => state.updateNodeForm); diff --git a/web/src/pages/data-flow/index.tsx b/web/src/pages/data-flow/index.tsx index 7dff6ab2d..d06a0c131 100644 --- a/web/src/pages/data-flow/index.tsx +++ b/web/src/pages/data-flow/index.tsx @@ -103,7 +103,6 @@ export default function DataFlow() { const { handleCancel } = useCancelCurrentDataflow({ messageId, setMessageId, - hideLogSheet, }); const time = useWatchAgentChange(chatDrawerVisible); diff --git a/web/src/pages/data-flow/log-sheet/index.tsx b/web/src/pages/data-flow/log-sheet/index.tsx index a907ce52e..88a6eff97 100644 --- a/web/src/pages/data-flow/log-sheet/index.tsx +++ b/web/src/pages/data-flow/log-sheet/index.tsx @@ -57,16 +57,16 @@ export function LogSheet({ {isParsing ? ( ) : (