mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Add child nodes and their connecting lines by clicking #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
import { IAgentNode } from '@/interfaces/database/flow';
|
import { IAgentNode } from '@/interfaces/database/flow';
|
||||||
import { Handle, NodeProps, Position } from '@xyflow/react';
|
import { Handle, NodeProps, Position } from '@xyflow/react';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { Operator } from '../../constant';
|
import { NodeHandleId, Operator } from '../../constant';
|
||||||
import useGraphStore from '../../store';
|
import useGraphStore from '../../store';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||||
@ -31,21 +31,22 @@ function InnerAgentNode({
|
|||||||
{isNotParentAgent && (
|
{isNotParentAgent && (
|
||||||
<>
|
<>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
id="c"
|
type="target"
|
||||||
type="source"
|
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
style={LeftHandleStyle}
|
style={LeftHandleStyle}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
id={NodeHandleId.End}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
type="source"
|
type="source"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
className={styles.handle}
|
className={styles.handle}
|
||||||
id="b"
|
|
||||||
style={RightHandleStyle}
|
style={RightHandleStyle}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
id={NodeHandleId.Start}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import {
|
import {
|
||||||
BeginQueryType,
|
BeginQueryType,
|
||||||
BeginQueryTypeIconMap,
|
BeginQueryTypeIconMap,
|
||||||
|
NodeHandleId,
|
||||||
Operator,
|
Operator,
|
||||||
} from '../../constant';
|
} from '../../constant';
|
||||||
import { BeginQuery } from '../../interface';
|
import { BeginQuery } from '../../interface';
|
||||||
@ -27,9 +28,9 @@ function InnerBeginNode({ data, id }: NodeProps<IBeginNode>) {
|
|||||||
type="source"
|
type="source"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
isConnectable
|
isConnectable
|
||||||
className={styles.handle}
|
|
||||||
style={RightHandleStyle}
|
style={RightHandleStyle}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
id={NodeHandleId.Start}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
|
|
||||||
<section className="flex items-center justify-center gap-2">
|
<section className="flex items-center justify-center gap-2">
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { ICategorizeNode } from '@/interfaces/database/flow';
|
|||||||
import { NodeProps, Position } from '@xyflow/react';
|
import { NodeProps, Position } from '@xyflow/react';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { NodeHandleId } from '../../constant';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { RightHandleStyle } from './handle-icon';
|
import { RightHandleStyle } from './handle-icon';
|
||||||
import NodeHeader from './node-header';
|
import NodeHeader from './node-header';
|
||||||
@ -23,7 +24,7 @@ export function InnerCategorizeNode({
|
|||||||
type="target"
|
type="target"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable
|
isConnectable
|
||||||
id={'a'}
|
id={NodeHandleId.End}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ export function InnerCategorizeNode({
|
|||||||
isConnectable
|
isConnectable
|
||||||
style={{ ...RightHandleStyle, top: position.top }}
|
style={{ ...RightHandleStyle, top: position.top }}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -30,8 +30,8 @@ function OperatorItemList({ operators }: OperatorItemProps) {
|
|||||||
key={x}
|
key={x}
|
||||||
className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start"
|
className="hover:bg-background-card py-1 px-3 cursor-pointer rounded-sm flex gap-2 items-center justify-start"
|
||||||
onClick={addCanvasNode(x, {
|
onClick={addCanvasNode(x, {
|
||||||
id: nodeId,
|
nodeId,
|
||||||
sourceHandle: id,
|
id,
|
||||||
position,
|
position,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { IRagNode } from '@/interfaces/database/flow';
|
import { IRagNode } from '@/interfaces/database/flow';
|
||||||
import { NodeProps, Position } from '@xyflow/react';
|
import { NodeProps, Position } from '@xyflow/react';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { NodeHandleId } from '../../constant';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||||
import NodeHeader from './node-header';
|
import NodeHeader from './node-header';
|
||||||
@ -17,8 +18,8 @@ function InnerRagNode({
|
|||||||
<ToolBar selected={selected} id={id} label={data.label}>
|
<ToolBar selected={selected} id={id} label={data.label}>
|
||||||
<NodeWrapper>
|
<NodeWrapper>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
id="c"
|
id={NodeHandleId.End}
|
||||||
type="source"
|
type="target"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
style={LeftHandleStyle}
|
style={LeftHandleStyle}
|
||||||
@ -28,9 +29,10 @@ function InnerRagNode({
|
|||||||
type="source"
|
type="source"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
id="b"
|
id={NodeHandleId.Start}
|
||||||
style={RightHandleStyle}
|
style={RightHandleStyle}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
|
<NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
|
||||||
</NodeWrapper>
|
</NodeWrapper>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { Flex } from 'antd';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
import { NodeHandleId } from '../../constant';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
@ -22,20 +23,21 @@ function InnerMessageNode({
|
|||||||
<ToolBar selected={selected} id={id} label={data.label}>
|
<ToolBar selected={selected} id={id} label={data.label}>
|
||||||
<NodeWrapper>
|
<NodeWrapper>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
id="c"
|
type="target"
|
||||||
type="source"
|
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
style={LeftHandleStyle}
|
style={LeftHandleStyle}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
id={NodeHandleId.End}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
type="source"
|
type="source"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
style={RightHandleStyle}
|
style={RightHandleStyle}
|
||||||
id="b"
|
id={NodeHandleId.Start}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<NodeHeader
|
<NodeHeader
|
||||||
id={id}
|
id={id}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { Avatar, Flex } from 'antd';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { memo, useMemo } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
|
import { NodeHandleId } from '../../constant';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
@ -36,8 +37,8 @@ function InnerRetrievalNode({
|
|||||||
<ToolBar selected={selected} id={id} label={data.label}>
|
<ToolBar selected={selected} id={id} label={data.label}>
|
||||||
<NodeWrapper>
|
<NodeWrapper>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
id="c"
|
id={NodeHandleId.End}
|
||||||
type="source"
|
type="target"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
className={styles.handle}
|
className={styles.handle}
|
||||||
@ -45,13 +46,14 @@ function InnerRetrievalNode({
|
|||||||
nodeId={id}
|
nodeId={id}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<CommonHandle
|
<CommonHandle
|
||||||
|
id={NodeHandleId.Start}
|
||||||
type="source"
|
type="source"
|
||||||
position={Position.Right}
|
position={Position.Right}
|
||||||
isConnectable={isConnectable}
|
isConnectable={isConnectable}
|
||||||
className={styles.handle}
|
className={styles.handle}
|
||||||
style={RightHandleStyle}
|
style={RightHandleStyle}
|
||||||
id="b"
|
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<NodeHeader
|
<NodeHeader
|
||||||
id={id}
|
id={id}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Card, CardContent } from '@/components/ui/card';
|
|||||||
import { ISwitchCondition, ISwitchNode } from '@/interfaces/database/flow';
|
import { ISwitchCondition, ISwitchNode } from '@/interfaces/database/flow';
|
||||||
import { NodeProps, Position } from '@xyflow/react';
|
import { NodeProps, Position } from '@xyflow/react';
|
||||||
import { memo, useCallback } from 'react';
|
import { memo, useCallback } from 'react';
|
||||||
import { SwitchOperatorOptions } from '../../constant';
|
import { NodeHandleId, SwitchOperatorOptions } from '../../constant';
|
||||||
import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
|
import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
|
||||||
import { CommonHandle } from './handle';
|
import { CommonHandle } from './handle';
|
||||||
import { RightHandleStyle } from './handle-icon';
|
import { RightHandleStyle } from './handle-icon';
|
||||||
@ -65,8 +65,8 @@ function InnerSwitchNode({ id, data, selected }: NodeProps<ISwitchNode>) {
|
|||||||
type="target"
|
type="target"
|
||||||
position={Position.Left}
|
position={Position.Left}
|
||||||
isConnectable
|
isConnectable
|
||||||
id={'a'}
|
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
id={NodeHandleId.End}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
<NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
|
<NodeHeader id={id} name={data.name} label={data.label}></NodeHeader>
|
||||||
<section className="gap-2.5 flex flex-col">
|
<section className="gap-2.5 flex flex-col">
|
||||||
@ -96,6 +96,7 @@ function InnerSwitchNode({ id, data, selected }: NodeProps<ISwitchNode>) {
|
|||||||
isConnectable
|
isConnectable
|
||||||
style={{ ...RightHandleStyle, top: position.top }}
|
style={{ ...RightHandleStyle, top: position.top }}
|
||||||
nodeId={id}
|
nodeId={id}
|
||||||
|
isConnectableEnd={false}
|
||||||
></CommonHandle>
|
></CommonHandle>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3008,3 +3008,8 @@ export const NoDebugOperatorsList = [
|
|||||||
Operator.Switch,
|
Operator.Switch,
|
||||||
Operator.Iteration,
|
Operator.Iteration,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export enum NodeHandleId {
|
||||||
|
Start = 'start',
|
||||||
|
End = 'end',
|
||||||
|
}
|
||||||
|
|||||||
@ -112,7 +112,7 @@ const AgentForm = ({ node }: INextOperatorForm) => {
|
|||||||
</FormContainer>
|
</FormContainer>
|
||||||
<BlockButton
|
<BlockButton
|
||||||
onClick={addCanvasNode(Operator.Agent, {
|
onClick={addCanvasNode(Operator.Agent, {
|
||||||
id: node?.id,
|
nodeId: node?.id,
|
||||||
position: Position.Bottom,
|
position: Position.Bottom,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import { useFetchModelId } from '@/hooks/logic-hooks';
|
import { useFetchModelId } from '@/hooks/logic-hooks';
|
||||||
import { Node, Position, ReactFlowInstance } from '@xyflow/react';
|
import { Connection, Node, Position, ReactFlowInstance } from '@xyflow/react';
|
||||||
import humanId from 'human-id';
|
import humanId from 'human-id';
|
||||||
import { lowerFirst } from 'lodash';
|
import { lowerFirst } from 'lodash';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
|
NodeHandleId,
|
||||||
NodeMap,
|
NodeMap,
|
||||||
Operator,
|
Operator,
|
||||||
initialAgentValues,
|
initialAgentValues,
|
||||||
@ -145,8 +146,8 @@ export function useCalculateNewlyChildPosition() {
|
|||||||
const maxY = Math.max(...yAxises);
|
const maxY = Math.max(...yAxises);
|
||||||
|
|
||||||
const position = {
|
const position = {
|
||||||
y: yAxises.length > 0 ? maxY + 262 : (parentNode?.position.y || 0) + 82,
|
y: yAxises.length > 0 ? maxY + 150 : parentNode?.position.y || 0,
|
||||||
x: (parentNode?.position.x || 0) + 140,
|
x: (parentNode?.position.x || 0) + 300,
|
||||||
};
|
};
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
@ -157,6 +158,31 @@ export function useCalculateNewlyChildPosition() {
|
|||||||
return { calculateNewlyBackChildPosition };
|
return { calculateNewlyBackChildPosition };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useAddChildEdge() {
|
||||||
|
const addEdge = useGraphStore((state) => state.addEdge);
|
||||||
|
|
||||||
|
const addChildEdge = useCallback(
|
||||||
|
(position: Position = Position.Right, edge: Partial<Connection>) => {
|
||||||
|
if (
|
||||||
|
position === Position.Right &&
|
||||||
|
edge.source &&
|
||||||
|
edge.target &&
|
||||||
|
edge.sourceHandle
|
||||||
|
) {
|
||||||
|
addEdge({
|
||||||
|
source: edge.source,
|
||||||
|
target: edge.target,
|
||||||
|
sourceHandle: edge.sourceHandle,
|
||||||
|
targetHandle: NodeHandleId.End,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[addEdge],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { addChildEdge };
|
||||||
|
}
|
||||||
|
|
||||||
export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
||||||
const addNode = useGraphStore((state) => state.addNode);
|
const addNode = useGraphStore((state) => state.addNode);
|
||||||
const getNode = useGraphStore((state) => state.getNode);
|
const getNode = useGraphStore((state) => state.getNode);
|
||||||
@ -166,18 +192,19 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
|||||||
const getNodeName = useGetNodeName();
|
const getNodeName = useGetNodeName();
|
||||||
const initializeOperatorParams = useInitializeOperatorParams();
|
const initializeOperatorParams = useInitializeOperatorParams();
|
||||||
const { calculateNewlyBackChildPosition } = useCalculateNewlyChildPosition();
|
const { calculateNewlyBackChildPosition } = useCalculateNewlyChildPosition();
|
||||||
|
const { addChildEdge } = useAddChildEdge();
|
||||||
// const [reactFlowInstance, setReactFlowInstance] =
|
// const [reactFlowInstance, setReactFlowInstance] =
|
||||||
// useState<ReactFlowInstance<any, any>>();
|
// useState<ReactFlowInstance<any, any>>();
|
||||||
|
|
||||||
const addCanvasNode = useCallback(
|
const addCanvasNode = useCallback(
|
||||||
(
|
(
|
||||||
type: string,
|
type: string,
|
||||||
params: { id?: string; position?: Position; sourceHandle?: string } = {
|
params: { nodeId?: string; position: Position; id?: string } = {
|
||||||
position: Position.Right,
|
position: Position.Right,
|
||||||
},
|
},
|
||||||
) =>
|
) =>
|
||||||
(event: React.MouseEvent<HTMLElement>) => {
|
(event: React.MouseEvent<HTMLElement>) => {
|
||||||
const id = params.id;
|
const nodeId = params.nodeId;
|
||||||
|
|
||||||
// reactFlowInstance.project was renamed to reactFlowInstance.screenToFlowPosition
|
// reactFlowInstance.project was renamed to reactFlowInstance.screenToFlowPosition
|
||||||
// and you don't need to subtract the reactFlowBounds.left/top anymore
|
// and you don't need to subtract the reactFlowBounds.left/top anymore
|
||||||
@ -188,7 +215,7 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (params.position === Position.Right) {
|
if (params.position === Position.Right) {
|
||||||
position = calculateNewlyBackChildPosition(id, params.sourceHandle);
|
position = calculateNewlyBackChildPosition(nodeId, params.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newNode: Node<any> = {
|
const newNode: Node<any> = {
|
||||||
@ -229,12 +256,15 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
|||||||
};
|
};
|
||||||
addNode(newNode);
|
addNode(newNode);
|
||||||
addNode(iterationStartNode);
|
addNode(iterationStartNode);
|
||||||
} else if (type === Operator.Agent) {
|
} else if (
|
||||||
const agentNode = getNode(id);
|
type === Operator.Agent &&
|
||||||
|
params.position === Position.Bottom
|
||||||
|
) {
|
||||||
|
const agentNode = getNode(nodeId);
|
||||||
if (agentNode) {
|
if (agentNode) {
|
||||||
// Calculate the coordinates of child nodes to prevent newly added child nodes from covering other child nodes
|
// Calculate the coordinates of child nodes to prevent newly added child nodes from covering other child nodes
|
||||||
const allChildAgentNodeIds = edges
|
const allChildAgentNodeIds = edges
|
||||||
.filter((x) => x.source === id && x.sourceHandle === 'e')
|
.filter((x) => x.source === nodeId && x.sourceHandle === 'e')
|
||||||
.map((x) => x.target);
|
.map((x) => x.target);
|
||||||
|
|
||||||
const xAxises = nodes
|
const xAxises = nodes
|
||||||
@ -249,9 +279,9 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
addNode(newNode);
|
addNode(newNode);
|
||||||
if (id) {
|
if (nodeId) {
|
||||||
addEdge({
|
addEdge({
|
||||||
source: id,
|
source: nodeId,
|
||||||
target: newNode.id,
|
target: newNode.id,
|
||||||
sourceHandle: 'e',
|
sourceHandle: 'e',
|
||||||
targetHandle: 'f',
|
targetHandle: 'f',
|
||||||
@ -268,11 +298,18 @@ export function useAddNode(reactFlowInstance?: ReactFlowInstance<any, any>) {
|
|||||||
newNode.extent = 'parent';
|
newNode.extent = 'parent';
|
||||||
}
|
}
|
||||||
addNode(newNode);
|
addNode(newNode);
|
||||||
|
addChildEdge(params.position, {
|
||||||
|
source: params.nodeId,
|
||||||
|
target: newNode.id,
|
||||||
|
sourceHandle: params.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
addChildEdge,
|
||||||
addEdge,
|
addEdge,
|
||||||
addNode,
|
addNode,
|
||||||
|
calculateNewlyBackChildPosition,
|
||||||
edges,
|
edges,
|
||||||
getNode,
|
getNode,
|
||||||
getNodeName,
|
getNodeName,
|
||||||
|
|||||||
Reference in New Issue
Block a user