mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Feature/agent UI style optimization (#10385)
### What problem does this PR solve? Hi team, @ZhenhangTung @KevinHuSh @cike8899 About #10384 , I've completed the UI optimization adjustments for the Agent page according to our previous discussions and the design draft sketches provided by @Naomi. The main modifications include: 1. Adjusted the style and content of placeholder-node. 2. Adjusted the location of the dropdown (to the right of the placeholder-node) . 3. Adjusted the tooltip position spacing when the mouse hovers in the dropdown menu. 4. Hides the thick scroll bar on the dropdown component. 5. Highlight the connection line when dragging to generate a placeholder-node <img width="1323" height="509" alt="Image" src="https://github.com/user-attachments/assets/0d366f7f-477d-4c00-bb58-d5d58b3a745f" /> Please review the related code modifications when you have time. Let me know if further adjustments are needed! Thanks! ### Type of change - [x] Other (please describe): UI Enhancement --------- Co-authored-by: leonlai <leonlai@futurefab.ai>
This commit is contained in:
@ -30,6 +30,10 @@ function InnerButtonEdge({
|
|||||||
sourceHandleId,
|
sourceHandleId,
|
||||||
}: EdgeProps<Edge<{ isHovered: boolean }>>) {
|
}: EdgeProps<Edge<{ isHovered: boolean }>>) {
|
||||||
const deleteEdgeById = useGraphStore((state) => state.deleteEdgeById);
|
const deleteEdgeById = useGraphStore((state) => state.deleteEdgeById);
|
||||||
|
const highlightedPlaceholderEdgeId = useGraphStore(
|
||||||
|
(state) => state.highlightedPlaceholderEdgeId,
|
||||||
|
);
|
||||||
|
|
||||||
const [edgePath, labelX, labelY] = getBezierPath({
|
const [edgePath, labelX, labelY] = getBezierPath({
|
||||||
sourceX,
|
sourceX,
|
||||||
sourceY,
|
sourceY,
|
||||||
@ -42,6 +46,13 @@ function InnerButtonEdge({
|
|||||||
return selected ? { strokeWidth: 1, stroke: 'var(--accent-primary)' } : {};
|
return selected ? { strokeWidth: 1, stroke: 'var(--accent-primary)' } : {};
|
||||||
}, [selected]);
|
}, [selected]);
|
||||||
|
|
||||||
|
const placeholderHighlightStyle = useMemo(() => {
|
||||||
|
const isHighlighted = highlightedPlaceholderEdgeId === id;
|
||||||
|
return isHighlighted
|
||||||
|
? { strokeWidth: 2, stroke: 'var(--accent-primary)' }
|
||||||
|
: {};
|
||||||
|
}, [highlightedPlaceholderEdgeId, id]);
|
||||||
|
|
||||||
const onEdgeClick = () => {
|
const onEdgeClick = () => {
|
||||||
deleteEdgeById(id);
|
deleteEdgeById(id);
|
||||||
};
|
};
|
||||||
@ -79,7 +90,12 @@ function InnerButtonEdge({
|
|||||||
<BaseEdge
|
<BaseEdge
|
||||||
path={edgePath}
|
path={edgePath}
|
||||||
markerEnd={markerEnd}
|
markerEnd={markerEnd}
|
||||||
style={{ ...style, ...selectedStyle, ...showHighlight }}
|
style={{
|
||||||
|
...style,
|
||||||
|
...selectedStyle,
|
||||||
|
...showHighlight,
|
||||||
|
...placeholderHighlightStyle,
|
||||||
|
}}
|
||||||
className={cn('text-text-secondary')}
|
className={cn('text-text-secondary')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@ -182,8 +182,12 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
|
|
||||||
const { clearActiveDropdown } = useDropdownManager();
|
const { clearActiveDropdown } = useDropdownManager();
|
||||||
|
|
||||||
const { removePlaceholderNode, onNodeCreated, setCreatedPlaceholderRef } =
|
const {
|
||||||
usePlaceholderManager(reactFlowInstance);
|
removePlaceholderNode,
|
||||||
|
onNodeCreated,
|
||||||
|
setCreatedPlaceholderRef,
|
||||||
|
checkAndRemoveExistingPlaceholder,
|
||||||
|
} = usePlaceholderManager(reactFlowInstance);
|
||||||
|
|
||||||
const { calculateDropdownPosition } = useDropdownPosition(reactFlowInstance);
|
const { calculateDropdownPosition } = useDropdownPosition(reactFlowInstance);
|
||||||
|
|
||||||
@ -204,6 +208,7 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
|
|||||||
calculateDropdownPosition,
|
calculateDropdownPosition,
|
||||||
removePlaceholderNode,
|
removePlaceholderNode,
|
||||||
clearActiveDropdown,
|
clearActiveDropdown,
|
||||||
|
checkAndRemoveExistingPlaceholder,
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPaneClick = useCallback(() => {
|
const onPaneClick = useCallback(() => {
|
||||||
|
|||||||
@ -107,7 +107,7 @@ function OperatorItemList({
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
)}
|
)}
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="right">
|
<TooltipContent side="right" sideOffset={24}>
|
||||||
<p>{t(`flow.${lowerFirst(operator)}Description`)}</p>
|
<p>{t(`flow.${lowerFirst(operator)}Description`)}</p>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -127,7 +127,7 @@ function AccordionOperators({
|
|||||||
return (
|
return (
|
||||||
<Accordion
|
<Accordion
|
||||||
type="multiple"
|
type="multiple"
|
||||||
className="px-2 text-text-title max-h-[45vh] overflow-auto"
|
className="px-2 text-text-title max-h-[45vh] overflow-auto scrollbar-none"
|
||||||
defaultValue={['item-1', 'item-2', 'item-3', 'item-4', 'item-5']}
|
defaultValue={['item-1', 'item-2', 'item-3', 'item-4', 'item-5']}
|
||||||
>
|
>
|
||||||
<AccordionItem value="item-1">
|
<AccordionItem value="item-1">
|
||||||
@ -249,7 +249,7 @@ export function InnerNextStepDropdown({
|
|||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
left: position.x,
|
left: position.x,
|
||||||
top: position.y + 10,
|
top: position.y,
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
}}
|
}}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
|||||||
@ -283,3 +283,16 @@
|
|||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hideScrollbar {
|
||||||
|
/* Webkit browsers (Chrome, Safari, Edge) */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
/* IE和Edge */
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,12 @@
|
|||||||
import { cn } from '@/lib/utils';
|
|
||||||
import { NodeProps, Position } from '@xyflow/react';
|
import { NodeProps, Position } from '@xyflow/react';
|
||||||
import { Skeleton } from 'antd';
|
import { Skeleton } from 'antd';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { NodeHandleId } from '../../constant';
|
||||||
import { NodeHandleId, Operator } from '../../constant';
|
|
||||||
import OperatorIcon from '../../operator-icon';
|
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { LeftHandleStyle } from './handle-icon';
|
import { LeftHandleStyle } from './handle-icon';
|
||||||
import styles from './index.less';
|
|
||||||
import { NodeWrapper } from './node-wrapper';
|
import { NodeWrapper } from './node-wrapper';
|
||||||
|
|
||||||
function InnerPlaceholderNode({ data, id, selected }: NodeProps) {
|
function InnerPlaceholderNode({ id, selected }: NodeProps) {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeWrapper selected={selected}>
|
<NodeWrapper selected={selected}>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
@ -25,20 +19,16 @@ function InnerPlaceholderNode({ data, id, selected }: NodeProps) {
|
|||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
|
|
||||||
<section className="flex items-center gap-2">
|
<section className="flex items-center gap-2">
|
||||||
<OperatorIcon name={data.label as Operator}></OperatorIcon>
|
<Skeleton.Avatar
|
||||||
<div className="truncate text-center font-semibold text-sm">
|
active
|
||||||
{t(`flow.placeholder`, 'Placeholder')}
|
size={24}
|
||||||
</div>
|
shape="square"
|
||||||
|
style={{ backgroundColor: 'rgba(255,255,255,0.05)' }}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<section className={'flex gap-2 flex-col'} style={{ marginTop: 10 }}>
|
||||||
className={cn(styles.generateParameters, 'flex gap-2 flex-col mt-2')}
|
<Skeleton.Input active style={{ width: '100%', height: 30 }} />
|
||||||
>
|
|
||||||
<Skeleton active paragraph={{ rows: 2 }} title={false} />
|
|
||||||
<div className="flex gap-2">
|
|
||||||
<Skeleton.Button active size="small" />
|
|
||||||
<Skeleton.Button active size="small" />
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
</NodeWrapper>
|
</NodeWrapper>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -965,4 +965,6 @@ export const DROPDOWN_ADDITIONAL_OFFSET = 50;
|
|||||||
export const HALF_PLACEHOLDER_NODE_WIDTH = PLACEHOLDER_NODE_WIDTH / 2;
|
export const HALF_PLACEHOLDER_NODE_WIDTH = PLACEHOLDER_NODE_WIDTH / 2;
|
||||||
export const HALF_PLACEHOLDER_NODE_HEIGHT =
|
export const HALF_PLACEHOLDER_NODE_HEIGHT =
|
||||||
PLACEHOLDER_NODE_HEIGHT + DROPDOWN_SPACING + DROPDOWN_ADDITIONAL_OFFSET;
|
PLACEHOLDER_NODE_HEIGHT + DROPDOWN_SPACING + DROPDOWN_ADDITIONAL_OFFSET;
|
||||||
|
export const DROPDOWN_HORIZONTAL_OFFSET = 28;
|
||||||
|
export const DROPDOWN_VERTICAL_OFFSET = 74;
|
||||||
export const PREVENT_CLOSE_DELAY = 300;
|
export const PREVENT_CLOSE_DELAY = 300;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useFetchAgent } from '@/hooks/use-agent-request';
|
import { useFetchAgent } from '@/hooks/use-agent-request';
|
||||||
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
import { RAGFlowNodeType } from '@/interfaces/database/flow';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { Operator } from '../constant';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
import { buildDslComponentsByGraph } from '../utils';
|
import { buildDslComponentsByGraph } from '../utils';
|
||||||
|
|
||||||
@ -10,15 +11,35 @@ export const useBuildDslData = () => {
|
|||||||
|
|
||||||
const buildDslData = useCallback(
|
const buildDslData = useCallback(
|
||||||
(currentNodes?: RAGFlowNodeType[]) => {
|
(currentNodes?: RAGFlowNodeType[]) => {
|
||||||
|
const nodesToProcess = currentNodes ?? nodes;
|
||||||
|
|
||||||
|
// Filter out placeholder nodes and related edges
|
||||||
|
const filteredNodes = nodesToProcess.filter(
|
||||||
|
(node) => node.data?.label !== Operator.Placeholder,
|
||||||
|
);
|
||||||
|
|
||||||
|
const filteredEdges = edges.filter((edge) => {
|
||||||
|
const sourceNode = nodesToProcess.find(
|
||||||
|
(node) => node.id === edge.source,
|
||||||
|
);
|
||||||
|
const targetNode = nodesToProcess.find(
|
||||||
|
(node) => node.id === edge.target,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
sourceNode?.data?.label !== Operator.Placeholder &&
|
||||||
|
targetNode?.data?.label !== Operator.Placeholder
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
const dslComponents = buildDslComponentsByGraph(
|
const dslComponents = buildDslComponentsByGraph(
|
||||||
currentNodes ?? nodes,
|
filteredNodes,
|
||||||
edges,
|
filteredEdges,
|
||||||
data.dsl.components,
|
data.dsl.components,
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...data.dsl,
|
...data.dsl,
|
||||||
graph: { nodes: currentNodes ?? nodes, edges },
|
graph: { nodes: filteredNodes, edges: filteredEdges },
|
||||||
components: dslComponents,
|
components: dslComponents,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { Connection, Position } from '@xyflow/react';
|
|||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
import { useDropdownManager } from '../canvas/context';
|
import { useDropdownManager } from '../canvas/context';
|
||||||
import { Operator, PREVENT_CLOSE_DELAY } from '../constant';
|
import { Operator, PREVENT_CLOSE_DELAY } from '../constant';
|
||||||
|
import useGraphStore from '../store';
|
||||||
import { useAddNode } from './use-add-node';
|
import { useAddNode } from './use-add-node';
|
||||||
|
|
||||||
interface ConnectionStartParams {
|
interface ConnectionStartParams {
|
||||||
@ -26,6 +27,7 @@ export const useConnectionDrag = (
|
|||||||
) => { x: number; y: number },
|
) => { x: number; y: number },
|
||||||
removePlaceholderNode: () => void,
|
removePlaceholderNode: () => void,
|
||||||
clearActiveDropdown: () => void,
|
clearActiveDropdown: () => void,
|
||||||
|
checkAndRemoveExistingPlaceholder: () => void,
|
||||||
) => {
|
) => {
|
||||||
// Reference for whether connection is established
|
// Reference for whether connection is established
|
||||||
const isConnectedRef = useRef(false);
|
const isConnectedRef = useRef(false);
|
||||||
@ -38,6 +40,7 @@ export const useConnectionDrag = (
|
|||||||
|
|
||||||
const { addCanvasNode } = useAddNode(reactFlowInstance);
|
const { addCanvasNode } = useAddNode(reactFlowInstance);
|
||||||
const { setActiveDropdown } = useDropdownManager();
|
const { setActiveDropdown } = useDropdownManager();
|
||||||
|
const { setHighlightedPlaceholderEdgeId } = useGraphStore();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connection start handler function
|
* Connection start handler function
|
||||||
@ -81,10 +84,17 @@ export const useConnectionDrag = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isHandleClick) {
|
if (isHandleClick) {
|
||||||
|
removePlaceholderNode();
|
||||||
|
hideModal();
|
||||||
|
clearActiveDropdown();
|
||||||
connectionStartRef.current = null;
|
connectionStartRef.current = null;
|
||||||
mouseStartPosRef.current = null;
|
mouseStartPosRef.current = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check and remove existing placeholder-node before creating new one
|
||||||
|
checkAndRemoveExistingPlaceholder();
|
||||||
|
|
||||||
// Create placeholder node and establish connection
|
// Create placeholder node and establish connection
|
||||||
const mockEvent = { clientX, clientY };
|
const mockEvent = { clientX, clientY };
|
||||||
const contextData = {
|
const contextData = {
|
||||||
@ -101,9 +111,13 @@ export const useConnectionDrag = (
|
|||||||
contextData,
|
contextData,
|
||||||
)(mockEvent);
|
)(mockEvent);
|
||||||
|
|
||||||
// Record the created placeholder node ID
|
|
||||||
if (newNodeId) {
|
if (newNodeId) {
|
||||||
setCreatedPlaceholderRef(newNodeId);
|
setCreatedPlaceholderRef(newNodeId);
|
||||||
|
|
||||||
|
if (connectionStartRef.current) {
|
||||||
|
const edgeId = `xy-edge__${connectionStartRef.current.nodeId}${connectionStartRef.current.handleId}-${newNodeId}end`;
|
||||||
|
setHighlightedPlaceholderEdgeId(edgeId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate placeholder node position and display dropdown menu
|
// Calculate placeholder node position and display dropdown menu
|
||||||
@ -140,6 +154,11 @@ export const useConnectionDrag = (
|
|||||||
calculateDropdownPosition,
|
calculateDropdownPosition,
|
||||||
setActiveDropdown,
|
setActiveDropdown,
|
||||||
showModal,
|
showModal,
|
||||||
|
setHighlightedPlaceholderEdgeId,
|
||||||
|
checkAndRemoveExistingPlaceholder,
|
||||||
|
removePlaceholderNode,
|
||||||
|
hideModal,
|
||||||
|
clearActiveDropdown,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -187,7 +206,13 @@ export const useConnectionDrag = (
|
|||||||
removePlaceholderNode();
|
removePlaceholderNode();
|
||||||
hideModal();
|
hideModal();
|
||||||
clearActiveDropdown();
|
clearActiveDropdown();
|
||||||
}, [removePlaceholderNode, hideModal, clearActiveDropdown]);
|
setHighlightedPlaceholderEdgeId(null);
|
||||||
|
}, [
|
||||||
|
removePlaceholderNode,
|
||||||
|
hideModal,
|
||||||
|
clearActiveDropdown,
|
||||||
|
setHighlightedPlaceholderEdgeId,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onConnectStart,
|
onConnectStart,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import {
|
import {
|
||||||
HALF_PLACEHOLDER_NODE_HEIGHT,
|
DROPDOWN_HORIZONTAL_OFFSET,
|
||||||
|
DROPDOWN_VERTICAL_OFFSET,
|
||||||
HALF_PLACEHOLDER_NODE_WIDTH,
|
HALF_PLACEHOLDER_NODE_WIDTH,
|
||||||
} from '../constant';
|
} from '../constant';
|
||||||
|
|
||||||
@ -29,8 +30,11 @@ export const useDropdownPosition = (reactFlowInstance: any) => {
|
|||||||
|
|
||||||
// Calculate dropdown position in flow coordinate system
|
// Calculate dropdown position in flow coordinate system
|
||||||
const dropdownFlowPosition = {
|
const dropdownFlowPosition = {
|
||||||
x: placeholderNodePosition.x - HALF_PLACEHOLDER_NODE_WIDTH, // Placeholder node left-aligned offset
|
x:
|
||||||
y: placeholderNodePosition.y + HALF_PLACEHOLDER_NODE_HEIGHT, // Placeholder node height plus spacing
|
placeholderNodePosition.x +
|
||||||
|
HALF_PLACEHOLDER_NODE_WIDTH +
|
||||||
|
DROPDOWN_HORIZONTAL_OFFSET,
|
||||||
|
y: placeholderNodePosition.y - DROPDOWN_VERTICAL_OFFSET,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert flow coordinates back to screen coordinates
|
// Convert flow coordinates back to screen coordinates
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { useCallback, useRef } from 'react';
|
import { useCallback, useRef } from 'react';
|
||||||
|
import { Operator } from '../constant';
|
||||||
import useGraphStore from '../store';
|
import useGraphStore from '../store';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,6 +12,46 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
// Flag indicating whether user has selected a node
|
// Flag indicating whether user has selected a node
|
||||||
const userSelectedNodeRef = useRef(false);
|
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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear highlighted placeholder edge
|
||||||
|
useGraphStore.getState().setHighlightedPlaceholderEdgeId(null);
|
||||||
|
|
||||||
|
// Update ref reference
|
||||||
|
if (createdPlaceholderRef.current === existingPlaceholder.id) {
|
||||||
|
createdPlaceholderRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [reactFlowInstance]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to remove placeholder node
|
* Function to remove placeholder node
|
||||||
* Called when user clicks blank area or cancels operation
|
* Called when user clicks blank area or cancels operation
|
||||||
@ -21,7 +62,8 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
reactFlowInstance &&
|
reactFlowInstance &&
|
||||||
!userSelectedNodeRef.current
|
!userSelectedNodeRef.current
|
||||||
) {
|
) {
|
||||||
const { nodes, edges } = useGraphStore.getState();
|
const { nodes, edges, setHighlightedPlaceholderEdgeId } =
|
||||||
|
useGraphStore.getState();
|
||||||
|
|
||||||
// Remove edges related to placeholder
|
// Remove edges related to placeholder
|
||||||
const edgesToRemove = edges.filter(
|
const edgesToRemove = edges.filter(
|
||||||
@ -42,6 +84,8 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHighlightedPlaceholderEdgeId(null);
|
||||||
|
|
||||||
createdPlaceholderRef.current = null;
|
createdPlaceholderRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +101,13 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
(newNodeId: string) => {
|
(newNodeId: string) => {
|
||||||
// First establish connection between new node and source, then delete placeholder
|
// First establish connection between new node and source, then delete placeholder
|
||||||
if (createdPlaceholderRef.current && reactFlowInstance) {
|
if (createdPlaceholderRef.current && reactFlowInstance) {
|
||||||
const { nodes, edges, addEdge, updateNode } = useGraphStore.getState();
|
const {
|
||||||
|
nodes,
|
||||||
|
edges,
|
||||||
|
addEdge,
|
||||||
|
updateNode,
|
||||||
|
setHighlightedPlaceholderEdgeId,
|
||||||
|
} = useGraphStore.getState();
|
||||||
|
|
||||||
// Find placeholder node to get its position
|
// Find placeholder node to get its position
|
||||||
const placeholderNode = nodes.find(
|
const placeholderNode = nodes.find(
|
||||||
@ -107,6 +157,8 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
edges: edgesToRemove,
|
edges: edgesToRemove,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setHighlightedPlaceholderEdgeId(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark that user has selected a node
|
// Mark that user has selected a node
|
||||||
@ -135,6 +187,7 @@ export const usePlaceholderManager = (reactFlowInstance: any) => {
|
|||||||
onNodeCreated,
|
onNodeCreated,
|
||||||
setCreatedPlaceholderRef,
|
setCreatedPlaceholderRef,
|
||||||
resetUserSelectedFlag,
|
resetUserSelectedFlag,
|
||||||
|
checkAndRemoveExistingPlaceholder,
|
||||||
createdPlaceholderRef: createdPlaceholderRef.current,
|
createdPlaceholderRef: createdPlaceholderRef.current,
|
||||||
userSelectedNodeRef: userSelectedNodeRef.current,
|
userSelectedNodeRef: userSelectedNodeRef.current,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export type RFState = {
|
|||||||
selectedEdgeIds: string[];
|
selectedEdgeIds: string[];
|
||||||
clickedNodeId: string; // currently selected node
|
clickedNodeId: string; // currently selected node
|
||||||
clickedToolId: string; // currently selected tool id
|
clickedToolId: string; // currently selected tool id
|
||||||
|
highlightedPlaceholderEdgeId: string | null;
|
||||||
onNodesChange: OnNodesChange<RAGFlowNodeType>;
|
onNodesChange: OnNodesChange<RAGFlowNodeType>;
|
||||||
onEdgesChange: OnEdgesChange;
|
onEdgesChange: OnEdgesChange;
|
||||||
onEdgeMouseEnter?: EdgeMouseHandler<Edge>;
|
onEdgeMouseEnter?: EdgeMouseHandler<Edge>;
|
||||||
@ -89,6 +90,7 @@ export type RFState = {
|
|||||||
) => void; // Deleting a condition of a classification operator will delete the related edge
|
) => void; // Deleting a condition of a classification operator will delete the related edge
|
||||||
findAgentToolNodeById: (id: string | null) => string | undefined;
|
findAgentToolNodeById: (id: string | null) => string | undefined;
|
||||||
selectNodeIds: (nodeIds: string[]) => void;
|
selectNodeIds: (nodeIds: string[]) => void;
|
||||||
|
setHighlightedPlaceholderEdgeId: (edgeId: string | null) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this is our useStore hook that we can use in our components to get parts of the store and call actions
|
// this is our useStore hook that we can use in our components to get parts of the store and call actions
|
||||||
@ -101,6 +103,7 @@ const useGraphStore = create<RFState>()(
|
|||||||
selectedEdgeIds: [] as string[],
|
selectedEdgeIds: [] as string[],
|
||||||
clickedNodeId: '',
|
clickedNodeId: '',
|
||||||
clickedToolId: '',
|
clickedToolId: '',
|
||||||
|
highlightedPlaceholderEdgeId: null,
|
||||||
onNodesChange: (changes) => {
|
onNodesChange: (changes) => {
|
||||||
set({
|
set({
|
||||||
nodes: applyNodeChanges(changes, get().nodes),
|
nodes: applyNodeChanges(changes, get().nodes),
|
||||||
@ -127,8 +130,9 @@ const useGraphStore = create<RFState>()(
|
|||||||
},
|
},
|
||||||
onConnect: (connection: Connection) => {
|
onConnect: (connection: Connection) => {
|
||||||
const { updateFormDataOnConnect } = get();
|
const { updateFormDataOnConnect } = get();
|
||||||
|
const newEdges = addEdge(connection, get().edges);
|
||||||
set({
|
set({
|
||||||
edges: addEdge(connection, get().edges),
|
edges: newEdges,
|
||||||
});
|
});
|
||||||
updateFormDataOnConnect(connection);
|
updateFormDataOnConnect(connection);
|
||||||
},
|
},
|
||||||
@ -526,6 +530,9 @@ const useGraphStore = create<RFState>()(
|
|||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
setHighlightedPlaceholderEdgeId: (edgeId) => {
|
||||||
|
set({ highlightedPlaceholderEdgeId: edgeId });
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
{ name: 'graph', trace: true },
|
{ name: 'graph', trace: true },
|
||||||
),
|
),
|
||||||
|
|||||||
@ -143,7 +143,7 @@ const buildOperatorParams = (operatorName: string) =>
|
|||||||
// initializeOperatorParams(operatorName), // Final processing, for guarantee
|
// initializeOperatorParams(operatorName), // Final processing, for guarantee
|
||||||
);
|
);
|
||||||
|
|
||||||
const ExcludeOperators = [Operator.Note, Operator.Tool];
|
const ExcludeOperators = [Operator.Note, Operator.Tool, Operator.Placeholder];
|
||||||
|
|
||||||
export function isBottomSubAgent(edges: Edge[], nodeId?: string) {
|
export function isBottomSubAgent(edges: Edge[], nodeId?: string) {
|
||||||
const edge = edges.find(
|
const edge = edges.find(
|
||||||
|
|||||||
Reference in New Issue
Block a user