mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-26 00:46:52 +08:00
### What problem does this PR solve? Fix: Fixed the issue where the connection lines of placeholder nodes in the agent canvas could not be displayed #9869 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
181 lines
5.4 KiB
TypeScript
181 lines
5.4 KiB
TypeScript
import { useCallback, useRef } from 'react';
|
|
import { Operator } from '../constant';
|
|
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);
|
|
|
|
/**
|
|
* Check if placeholder node exists and remove it if found
|
|
* Ensures only one placeholder can exist on the panel
|
|
*/
|
|
const checkAndRemoveExistingPlaceholder = useCallback(() => {
|
|
const { nodes, edges } = useGraphStore.getState();
|
|
|
|
// Find existing placeholder node
|
|
const existingPlaceholder = nodes.find(
|
|
(node) => node.data?.label === Operator.Placeholder,
|
|
);
|
|
|
|
if (existingPlaceholder && reactFlowInstance) {
|
|
// Remove edges related to placeholder
|
|
const edgesToRemove = edges.filter(
|
|
(edge) =>
|
|
edge.target === existingPlaceholder.id ||
|
|
edge.source === existingPlaceholder.id,
|
|
);
|
|
|
|
// Remove placeholder node
|
|
const nodesToRemove = [existingPlaceholder];
|
|
|
|
if (nodesToRemove.length > 0 || edgesToRemove.length > 0) {
|
|
reactFlowInstance.deleteElements({
|
|
nodes: nodesToRemove,
|
|
edges: edgesToRemove,
|
|
});
|
|
}
|
|
|
|
// Update ref reference
|
|
if (createdPlaceholderRef.current === existingPlaceholder.id) {
|
|
createdPlaceholderRef.current = null;
|
|
}
|
|
}
|
|
}, [reactFlowInstance]);
|
|
|
|
/**
|
|
* 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,
|
|
checkAndRemoveExistingPlaceholder,
|
|
createdPlaceholderRef: createdPlaceholderRef.current,
|
|
userSelectedNodeRef: userSelectedNodeRef.current,
|
|
};
|
|
};
|