mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-03 19:15:30 +08:00
Feat: Keep connection status during generating agent by drag and drop … (#10141)
### What problem does this PR solve? About issue #10140 In version 0.20.1, we implemented the generation of new node through mouse drag and drop. If we could create a workflow module like in Coze, where there is not only a dropdown menu but also an intermediate node (placeholder node) after the drag and drop is completed, this could improve the user experience. ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
141
web/src/pages/agent/hooks/use-placeholder-manager.ts
Normal file
141
web/src/pages/agent/hooks/use-placeholder-manager.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import useGraphStore from '../store';
|
||||
|
||||
/**
|
||||
* Placeholder node management Hook
|
||||
* Responsible for managing placeholder node creation, deletion, and state tracking
|
||||
*/
|
||||
export const usePlaceholderManager = (reactFlowInstance: any) => {
|
||||
// Reference to the created placeholder node ID
|
||||
const createdPlaceholderRef = useRef<string | null>(null);
|
||||
// Flag indicating whether user has selected a node
|
||||
const userSelectedNodeRef = useRef(false);
|
||||
|
||||
/**
|
||||
* Function to remove placeholder node
|
||||
* Called when user clicks blank area or cancels operation
|
||||
*/
|
||||
const removePlaceholderNode = useCallback(() => {
|
||||
if (
|
||||
createdPlaceholderRef.current &&
|
||||
reactFlowInstance &&
|
||||
!userSelectedNodeRef.current
|
||||
) {
|
||||
const { nodes, edges } = useGraphStore.getState();
|
||||
|
||||
// Remove edges related to placeholder
|
||||
const edgesToRemove = edges.filter(
|
||||
(edge) =>
|
||||
edge.target === createdPlaceholderRef.current ||
|
||||
edge.source === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
// Remove placeholder node
|
||||
const nodesToRemove = nodes.filter(
|
||||
(node) => node.id === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
if (nodesToRemove.length > 0 || edgesToRemove.length > 0) {
|
||||
reactFlowInstance.deleteElements({
|
||||
nodes: nodesToRemove,
|
||||
edges: edgesToRemove,
|
||||
});
|
||||
}
|
||||
|
||||
createdPlaceholderRef.current = null;
|
||||
}
|
||||
|
||||
// Reset user selection flag
|
||||
userSelectedNodeRef.current = false;
|
||||
}, [reactFlowInstance]);
|
||||
|
||||
/**
|
||||
* User node selection callback
|
||||
* Called when user selects a node type from dropdown menu
|
||||
*/
|
||||
const onNodeCreated = useCallback(
|
||||
(newNodeId: string) => {
|
||||
// First establish connection between new node and source, then delete placeholder
|
||||
if (createdPlaceholderRef.current && reactFlowInstance) {
|
||||
const { nodes, edges, addEdge, updateNode } = useGraphStore.getState();
|
||||
|
||||
// Find placeholder node to get its position
|
||||
const placeholderNode = nodes.find(
|
||||
(node) => node.id === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
// Find placeholder-related connection and get source node info
|
||||
const placeholderEdge = edges.find(
|
||||
(edge) => edge.target === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
// Update new node position to match placeholder position
|
||||
if (placeholderNode) {
|
||||
const newNode = nodes.find((node) => node.id === newNodeId);
|
||||
if (newNode) {
|
||||
updateNode({
|
||||
...newNode,
|
||||
position: placeholderNode.position,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (placeholderEdge) {
|
||||
// Establish connection between new node and source node
|
||||
addEdge({
|
||||
source: placeholderEdge.source,
|
||||
target: newNodeId,
|
||||
sourceHandle: placeholderEdge.sourceHandle || null,
|
||||
targetHandle: placeholderEdge.targetHandle || null,
|
||||
});
|
||||
}
|
||||
|
||||
// Remove placeholder node and related connections
|
||||
const edgesToRemove = edges.filter(
|
||||
(edge) =>
|
||||
edge.target === createdPlaceholderRef.current ||
|
||||
edge.source === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
const nodesToRemove = nodes.filter(
|
||||
(node) => node.id === createdPlaceholderRef.current,
|
||||
);
|
||||
|
||||
if (nodesToRemove.length > 0 || edgesToRemove.length > 0) {
|
||||
reactFlowInstance.deleteElements({
|
||||
nodes: nodesToRemove,
|
||||
edges: edgesToRemove,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Mark that user has selected a node
|
||||
userSelectedNodeRef.current = true;
|
||||
createdPlaceholderRef.current = null;
|
||||
},
|
||||
[reactFlowInstance],
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the created placeholder node ID
|
||||
*/
|
||||
const setCreatedPlaceholderRef = useCallback((nodeId: string | null) => {
|
||||
createdPlaceholderRef.current = nodeId;
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Reset user selection flag
|
||||
*/
|
||||
const resetUserSelectedFlag = useCallback(() => {
|
||||
userSelectedNodeRef.current = false;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
removePlaceholderNode,
|
||||
onNodeCreated,
|
||||
setCreatedPlaceholderRef,
|
||||
resetUserSelectedFlag,
|
||||
createdPlaceholderRef: createdPlaceholderRef.current,
|
||||
userSelectedNodeRef: userSelectedNodeRef.current,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user