diff --git a/packages/ai-workspace-common/src/components/canvas/index.tsx b/packages/ai-workspace-common/src/components/canvas/index.tsx index 0f959e30b..2ae934651 100644 --- a/packages/ai-workspace-common/src/components/canvas/index.tsx +++ b/packages/ai-workspace-common/src/components/canvas/index.tsx @@ -1,6 +1,13 @@ import { useCallback, useMemo, useEffect, useState, useRef, memo } from 'react'; import { useTranslation } from 'react-i18next'; -import { ReactFlow, Background, MiniMap, ReactFlowProvider, useReactFlow } from '@xyflow/react'; +import { + ReactFlow, + Background, + MiniMap, + ReactFlowProvider, + useReactFlow, + Node, +} from '@xyflow/react'; import { Button } from 'antd'; import { nodeTypes, CanvasNode } from './nodes'; import { LaunchPad } from './launchpad'; @@ -460,15 +467,20 @@ const Flow = memo(({ canvasId }: { canvasId: string }) => { const memoizedNodeTypes = useMemo(() => nodeTypes, []); // Optimize node dragging performance - const { setIsNodeDragging } = useEditorPerformance(); + const { setIsNodeDragging, setDraggingNodeId } = useEditorPerformance(); - const onNodeDragStart = useCallback(() => { - setIsNodeDragging(true); - }, [setIsNodeDragging]); + const onNodeDragStart = useCallback( + (_: React.MouseEvent, node: Node) => { + setIsNodeDragging(true); + setDraggingNodeId(node.id); + }, + [setIsNodeDragging, setDraggingNodeId], + ); const onNodeDragStop = useCallback(() => { setIsNodeDragging(false); - }, [setIsNodeDragging]); + setDraggingNodeId(null); + }, [setIsNodeDragging, setDraggingNodeId]); const onSelectionContextMenu = useCallback( (event: React.MouseEvent) => { diff --git a/packages/ai-workspace-common/src/components/canvas/nodes/document.tsx b/packages/ai-workspace-common/src/components/canvas/nodes/document.tsx index e556d14d8..c8c57f2cc 100644 --- a/packages/ai-workspace-common/src/components/canvas/nodes/document.tsx +++ b/packages/ai-workspace-common/src/components/canvas/nodes/document.tsx @@ -27,6 +27,7 @@ import { NodeHeader } from './shared/node-header'; import { ContentPreview } from './shared/content-preview'; import { useCreateDocument } from '@refly-packages/ai-workspace-common/hooks/canvas/use-create-document'; import { useDeleteDocument } from '@refly-packages/ai-workspace-common/hooks/canvas/use-delete-document'; +import { useEditorPerformance } from '@refly-packages/ai-workspace-common/context/editor-performance'; export const DocumentNode = memo( ({ @@ -50,7 +51,9 @@ export const DocumentNode = memo( operatingNodeId: state.operatingNodeId, })); + const { draggingNodeId } = useEditorPerformance(); const isOperating = operatingNodeId === id; + const isDragging = draggingNodeId === id; const sizeMode = data?.metadata?.sizeMode || 'adaptive'; const node = useMemo(() => getNode(id), [id, getNode]); @@ -199,7 +202,7 @@ export const DocumentNode = memo( onClick={onNodeClick} style={isPreview ? { width: 288, height: 200 } : containerStyle} > - {!isPreview && !hideActions && ( + {!isPreview && !hideActions && !isDragging && ( )} diff --git a/packages/ai-workspace-common/src/components/canvas/nodes/group.tsx b/packages/ai-workspace-common/src/components/canvas/nodes/group.tsx index cef5bd295..a7b061791 100644 --- a/packages/ai-workspace-common/src/components/canvas/nodes/group.tsx +++ b/packages/ai-workspace-common/src/components/canvas/nodes/group.tsx @@ -19,6 +19,7 @@ import { CanvasNodeType } from '@refly/openapi-schema'; import { useAddNode } from '@refly-packages/ai-workspace-common/hooks/canvas/use-add-node'; import { useNodeCluster } from '@refly-packages/ai-workspace-common/hooks/canvas/use-node-cluster'; import Moveable from 'react-moveable'; +import { useEditorPerformance } from '@refly-packages/ai-workspace-common/context/editor-performance'; interface GroupMetadata { label?: string; @@ -67,6 +68,8 @@ export const GroupNode = memo( // Memoize node and its measurements const node = useMemo(() => getNode(id), [id, getNode]); + const { draggingNodeId } = useEditorPerformance(); + const isDragging = draggingNodeId === id; const initialSize = useMemo( () => ({ @@ -317,7 +320,9 @@ export const GroupNode = memo( {!isPreview && !hideActions && ( <> - + {!isDragging && ( + + )} { @@ -43,7 +44,9 @@ export const ImageNode = memo( operatingNodeId: state.operatingNodeId, })); + const { draggingNodeId } = useEditorPerformance(); const isOperating = operatingNodeId === id; + const isDragging = draggingNodeId === id; const node = useMemo(() => getNode(id), [id, getNode]); const { containerStyle, handleResize } = useNodeSize({ @@ -182,7 +185,7 @@ export const ImageNode = memo( 'nodrag nopan select-text': isOperating, })} > - {!isPreview && !hideActions && ( + {!isPreview && !hideActions && !isDragging && ( )} diff --git a/packages/ai-workspace-common/src/components/canvas/nodes/resource.tsx b/packages/ai-workspace-common/src/components/canvas/nodes/resource.tsx index 8241d8cd1..b4c465d52 100644 --- a/packages/ai-workspace-common/src/components/canvas/nodes/resource.tsx +++ b/packages/ai-workspace-common/src/components/canvas/nodes/resource.tsx @@ -32,7 +32,7 @@ import { ContentPreview } from './shared/content-preview'; import { useCreateDocument } from '@refly-packages/ai-workspace-common/hooks/canvas/use-create-document'; import { message } from 'antd'; import getClient from '@refly-packages/ai-workspace-common/requests/proxiedRequest'; - +import { useEditorPerformance } from '@refly-packages/ai-workspace-common/context/editor-performance'; export const ResourceNode = memo( ({ id, data, isPreview, selected, hideActions, hideHandles, onNodeClick }: ResourceNodeProps) => { const [isHovered, setIsHovered] = useState(false); @@ -54,7 +54,9 @@ export const ResourceNode = memo( operatingNodeId: state.operatingNodeId, })); + const { draggingNodeId } = useEditorPerformance(); const isOperating = operatingNodeId === id; + const isDragging = draggingNodeId === id; const sizeMode = data?.metadata?.sizeMode || 'adaptive'; const node = useMemo(() => getNode(id), [id, getNode]); @@ -249,7 +251,7 @@ export const ResourceNode = memo( 'nodrag nopan select-text': isOperating, })} > - {!isPreview && !hideActions && ( + {!isPreview && !hideActions && !isDragging && ( )} diff --git a/packages/ai-workspace-common/src/components/canvas/nodes/skill-response.tsx b/packages/ai-workspace-common/src/components/canvas/nodes/skill-response.tsx index 7200357e9..7779bca61 100644 --- a/packages/ai-workspace-common/src/components/canvas/nodes/skill-response.tsx +++ b/packages/ai-workspace-common/src/components/canvas/nodes/skill-response.tsx @@ -2,7 +2,7 @@ import { Position, useReactFlow } from '@xyflow/react'; import { useTranslation } from 'react-i18next'; import Moveable from 'react-moveable'; import classNames from 'classnames'; -import { Divider, message } from 'antd'; +import { Divider, Input, message } from 'antd'; import { CanvasNode, SkillResponseNodeProps } from './shared/types'; import { useState, useCallback, useRef, useEffect, useMemo, memo } from 'react'; import { CustomHandle } from './shared/custom-handle'; @@ -47,11 +47,18 @@ import { NodeResizer as NodeResizerComponent } from './shared/node-resizer'; import { useNodeSize } from '@refly-packages/ai-workspace-common/hooks/canvas/use-node-size'; import { ContentPreview } from './shared/content-preview'; import { useActionPolling } from '@refly-packages/ai-workspace-common/hooks/canvas/use-action-polling'; - +import { useSetNodeDataByEntity } from '@refly-packages/ai-workspace-common/hooks/canvas/use-set-node-data-by-entity'; +import { useEditorPerformance } from '@refly-packages/ai-workspace-common/context/editor-performance'; const POLLING_WAIT_TIME = 15000; const NodeHeader = memo( - ({ query, skillName, skill }: { query: string; skillName: string; skill: any }) => { + ({ + query, + skillName, + skill, + updateTitle, + }: { query: string; skillName: string; skill: any; updateTitle: (title: string) => void }) => { + const [editTitle, setEditTitle] = useState(query); return ( <>
@@ -59,12 +66,20 @@ const NodeHeader = memo(
- { + setEditTitle(e.target.value); + updateTitle?.(e.target.value); + }} + /> + {/* {query} - + */}
{skillName && skillName !== 'commonQnA' && ( @@ -146,12 +161,14 @@ export const SkillResponseNode = memo( onNodeClick, }: SkillResponseNodeProps) => { const [isHovered, setIsHovered] = useState(false); + const { draggingNodeId } = useEditorPerformance(); + const isDragging = draggingNodeId === id; const { edges, operatingNodeId } = useCanvasStoreShallow((state) => ({ edges: state.data[state.currentCanvasId]?.edges ?? [], operatingNodeId: state.operatingNodeId, })); - + const setNodeDataByEntity = useSetNodeDataByEntity(); const patchNodeData = usePatchNodeData(); const { getNode } = useReactFlow(); const { handleMouseEnter: onHoverStart, handleMouseLeave: onHoverEnd } = useNodeHoverEffect(id); @@ -402,6 +419,18 @@ export const SkillResponseNode = memo( nodeActionEmitter.emit(createNodeEventName(id, 'cloneAskAI.completed')); }, [id, data?.entityId, addNode, t]); + const onTitleChange = (newTitle: string) => { + setNodeDataByEntity( + { + entityId: data.entityId, + type: 'skillResponse', + }, + { + title: newTitle, + }, + ); + }; + // Update size when content changes useEffect(() => { if (!targetRef.current) return; @@ -470,7 +499,7 @@ export const SkillResponseNode = memo( onMouseLeave={handleMouseLeave} onClick={onNodeClick} > - {!isPreview && !hideActions && ( + {!isPreview && !hideActions && !isDragging && ( )} @@ -499,7 +528,12 @@ export const SkillResponseNode = memo(
- +
diff --git a/packages/ai-workspace-common/src/components/canvas/nodes/skill.tsx b/packages/ai-workspace-common/src/components/canvas/nodes/skill.tsx index 313882de5..77233c24f 100644 --- a/packages/ai-workspace-common/src/components/canvas/nodes/skill.tsx +++ b/packages/ai-workspace-common/src/components/canvas/nodes/skill.tsx @@ -38,6 +38,7 @@ import { NodeResizer as NodeResizerComponent } from './shared/node-resizer'; import classNames from 'classnames'; import Moveable from 'react-moveable'; import { useUploadImage } from '@refly-packages/ai-workspace-common/hooks/use-upload-image'; +import { useEditorPerformance } from '@refly-packages/ai-workspace-common/context/editor-performance'; type SkillNode = Node, 'skill'>; @@ -115,7 +116,9 @@ export const SkillNode = memo( const { operatingNodeId } = useCanvasStoreShallow((state) => ({ operatingNodeId: state.operatingNodeId, })); + const { draggingNodeId } = useEditorPerformance(); const isOperating = operatingNodeId === id; + const isDragging = draggingNodeId === id; const node = useMemo(() => getNode(id), [id, getNode]); const { containerStyle, handleResize, updateSize } = useNodeSize({ id, @@ -344,7 +347,7 @@ export const SkillNode = memo( onMouseLeave={handleMouseLeave} style={containerStyle} > - + {!isDragging && }
void; + draggingNodeId: string | null; + setDraggingNodeId: (nodeId: string | null) => void; } const EditorPerformanceContext = createContext({ isNodeDragging: false, setIsNodeDragging: () => {}, + draggingNodeId: null, + setDraggingNodeId: () => {}, }); export const EditorPerformanceProvider = ({ children }) => { const [isNodeDragging, setIsNodeDragging] = useState(false); + const [draggingNodeId, setDraggingNodeId] = useState(null); return ( - + {children} );