diff --git a/web/app/components/workflow/comment/icon.tsx b/web/app/components/workflow/comment/icon.tsx index 3aecc7976d..20da86e606 100644 --- a/web/app/components/workflow/comment/icon.tsx +++ b/web/app/components/workflow/comment/icon.tsx @@ -1,5 +1,6 @@ import type { FC } from 'react' -import { memo } from 'react' +import { memo, useMemo } from 'react' +import { useReactFlow, useViewport } from 'reactflow' import Avatar from '@/app/components/base/avatar' import type { WorkflowCommentList } from '@/service/workflow-comment' @@ -9,12 +10,22 @@ type CommentIconProps = { } export const CommentIcon: FC = memo(({ comment, onClick }) => { + const { flowToScreenPosition } = useReactFlow() + const viewport = useViewport() + + const screenPosition = useMemo(() => { + return flowToScreenPosition({ + x: comment.position_x, + y: comment.position_y, + }) + }, [comment.position_x, comment.position_y, viewport.x, viewport.y, viewport.zoom, flowToScreenPosition]) + return (
= memo(({ comment, onClick }) =>
= memo(({ comment, onClick }) =>
) +}, (prevProps, nextProps) => { + return ( + prevProps.comment.id === nextProps.comment.id + && prevProps.comment.position_x === nextProps.comment.position_x + && prevProps.comment.position_y === nextProps.comment.position_y + && prevProps.onClick === nextProps.onClick + ) }) CommentIcon.displayName = 'CommentIcon' diff --git a/web/app/components/workflow/comment/input.tsx b/web/app/components/workflow/comment/input.tsx index 956cb884b0..8d12173fa3 100644 --- a/web/app/components/workflow/comment/input.tsx +++ b/web/app/components/workflow/comment/input.tsx @@ -1,7 +1,8 @@ import type { FC } from 'react' -import { memo, useCallback, useEffect, useRef, useState } from 'react' +import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import Textarea from 'react-textarea-autosize' import { RiSendPlane2Fill } from '@remixicon/react' +import { useReactFlow, useViewport } from 'reactflow' import cn from '@/utils/classnames' import Button from '@/app/components/base/button' import Avatar from '@/app/components/base/avatar' @@ -17,6 +18,12 @@ export const CommentInput: FC = memo(({ position, onSubmit, o const [content, setContent] = useState('') const textareaRef = useRef(null) const { userProfile } = useAppContext() + const { flowToScreenPosition } = useReactFlow() + const viewport = useViewport() + + const screenPosition = useMemo(() => { + return flowToScreenPosition(position) + }, [position.x, position.y, viewport.x, viewport.y, viewport.zoom, flowToScreenPosition]) useEffect(() => { const handleGlobalKeyDown = (e: KeyboardEvent) => { @@ -59,8 +66,8 @@ export const CommentInput: FC = memo(({ position, onSubmit, o
diff --git a/web/app/components/workflow/hooks/use-workflow-comment.ts b/web/app/components/workflow/hooks/use-workflow-comment.ts index 97cf8ac582..f8020de8eb 100644 --- a/web/app/components/workflow/hooks/use-workflow-comment.ts +++ b/web/app/components/workflow/hooks/use-workflow-comment.ts @@ -1,21 +1,22 @@ import { useCallback, useEffect, useState } from 'react' import { useParams } from 'next/navigation' +import { useReactFlow } from 'reactflow' import { useStore } from '../store' import { ControlMode } from '../types' -import type { WorkflowComment } from '@/service/workflow-comment' +import type { WorkflowCommentList } from '@/service/workflow-comment' import { createWorkflowComment, fetchWorkflowComments } from '@/service/workflow-comment' export const useWorkflowComment = () => { const params = useParams() const appId = params.appId as string + const reactflow = useReactFlow() const controlMode = useStore(s => s.controlMode) const setControlMode = useStore(s => s.setControlMode) const pendingComment = useStore(s => s.pendingComment) const setPendingComment = useStore(s => s.setPendingComment) - const [comments, setComments] = useState([]) + const [comments, setComments] = useState([]) const [loading, setLoading] = useState(false) - // 加载评论列表 const loadComments = useCallback(async () => { if (!appId) return @@ -32,7 +33,6 @@ export const useWorkflowComment = () => { } }, [appId]) - // 初始化时加载评论 useEffect(() => { loadComments() }, [loadComments]) @@ -56,47 +56,39 @@ export const useWorkflowComment = () => { }) console.log('Comment created successfully:', newComment) - setComments(prev => [...prev, newComment]) + await loadComments() setPendingComment(null) setControlMode(ControlMode.Pointer) } - catch (error) { + catch (error) { console.error('Failed to create comment:', error) setPendingComment(null) setControlMode(ControlMode.Pointer) } - }, [appId, pendingComment, setControlMode, setPendingComment, setComments]) + }, [appId, pendingComment, setControlMode, setPendingComment, loadComments]) const handleCommentCancel = useCallback(() => { setPendingComment(null) setControlMode(ControlMode.Pointer) }, [setControlMode, setPendingComment]) - const handleCommentIconClick = useCallback((comment: WorkflowComment) => { + const handleCommentIconClick = useCallback((comment: WorkflowCommentList) => { // TODO: display comment details console.log('Comment clicked:', comment) }, []) const handleCreateComment = useCallback((mousePosition: { pageX: number; pageY: number }) => { if (controlMode === ControlMode.Comment) { - const containerElement = document.querySelector('#workflow-container') - if (containerElement) { - const containerBounds = containerElement.getBoundingClientRect() - const position = { - x: mousePosition.pageX - containerBounds.left, - y: mousePosition.pageY - containerBounds.top, - } - console.log('Setting pending comment at position:', position) - setPendingComment(position) - } - else { - console.error('Could not find workflow container element') - } + const { screenToFlowPosition } = reactflow + const flowPosition = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY }) + + console.log('Setting pending comment at flow position:', flowPosition) + setPendingComment(flowPosition) } - else { + else { console.log('Control mode is not Comment:', controlMode) } - }, [controlMode, setPendingComment]) + }, [controlMode, setPendingComment, reactflow]) return { comments,