From 75257232c3b0e4f88adc924dd155ff387666a1ab Mon Sep 17 00:00:00 2001 From: hjlarry Date: Sun, 14 Sep 2025 12:10:37 +0800 Subject: [PATCH] add create comment frontend --- .../components/workflow/comment-manager.tsx | 21 +++ web/app/components/workflow/comment/index.tsx | 128 ++++++++++++++++++ web/app/components/workflow/hooks/index.ts | 1 + .../workflow/hooks/use-workflow-comment.ts | 86 ++++++++++++ web/app/components/workflow/index.tsx | 28 ++++ .../components/workflow/operator/control.tsx | 23 +++- web/app/components/workflow/operator/hooks.ts | 8 ++ .../workflow/store/workflow/workflow-slice.ts | 8 +- web/app/components/workflow/types.ts | 1 + web/i18n/en-US/workflow.ts | 1 + web/i18n/zh-Hans/workflow.ts | 1 + 11 files changed, 303 insertions(+), 3 deletions(-) create mode 100644 web/app/components/workflow/comment-manager.tsx create mode 100644 web/app/components/workflow/comment/index.tsx create mode 100644 web/app/components/workflow/hooks/use-workflow-comment.ts diff --git a/web/app/components/workflow/comment-manager.tsx b/web/app/components/workflow/comment-manager.tsx new file mode 100644 index 0000000000..58fa93fa3d --- /dev/null +++ b/web/app/components/workflow/comment-manager.tsx @@ -0,0 +1,21 @@ +import { useEventListener } from 'ahooks' +import { useWorkflowStore } from './store' +import { useWorkflowComment } from './hooks/use-workflow-comment' + +const CommentManager = () => { + const workflowStore = useWorkflowStore() + const { handleCreateComment } = useWorkflowComment() + + useEventListener('click', (e) => { + const { controlMode, mousePosition } = workflowStore.getState() + + if (controlMode === 'comment') { + e.preventDefault() + handleCreateComment(mousePosition) + } + }) + + return null +} + +export default CommentManager diff --git a/web/app/components/workflow/comment/index.tsx b/web/app/components/workflow/comment/index.tsx new file mode 100644 index 0000000000..17b31c9ee6 --- /dev/null +++ b/web/app/components/workflow/comment/index.tsx @@ -0,0 +1,128 @@ +import type { FC } from 'react' +import { memo, useCallback, useState } from 'react' +import { useTranslation } from 'react-i18next' +import { RiMessage3Line } from '@remixicon/react' +import { useStore } from '../store' +import { ControlMode } from '../types' +import type { WorkflowComment } from '@/service/workflow-comment' + +type CommentCursorProps = { + mousePosition: { elementX: number; elementY: number } +} + +export const CommentCursor: FC = memo(({ mousePosition }) => { + const controlMode = useStore(s => s.controlMode) + + if (controlMode !== ControlMode.Comment) + return null + + return ( +
+ +
+ ) +}) + +CommentCursor.displayName = 'CommentCursor' + +type CommentInputProps = { + position: { x: number; y: number } + onSubmit: (content: string) => void + onCancel: () => void +} + +export const CommentInput: FC = memo(({ position, onSubmit, onCancel }) => { + const { t } = useTranslation() + const [content, setContent] = useState('') + + const handleSubmit = useCallback(() => { + try { + if (content.trim()) { + onSubmit(content.trim()) + setContent('') + } + } + catch (error) { + console.error('Error in CommentInput handleSubmit:', error) + } + }, [content, onSubmit]) + + const handleKeyDown = useCallback((e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault() + handleSubmit() + } + else if (e.key === 'Escape') { + onCancel() + } + }, [handleSubmit, onCancel]) + + return ( +
+