Skip to content

Commit

Permalink
feat(Data Mapper): Move edge path logic to useInternal Reactflow state (
Browse files Browse the repository at this point in the history
#6139)

* find and hide handle

* update hook

* remove redux state
  • Loading branch information
takyyon authored Nov 19, 2024
1 parent 059c900 commit 9603d91
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 162 deletions.
1 change: 1 addition & 0 deletions libs/data-mapper-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"@react-hookz/web": "22.0.0",
"@reduxjs/toolkit": "1.8.5",
"@xyflow/react": "^12.0.3",
"@xyflow/system": "^0.0.37",
"elkjs": "0.9.1",
"fuse.js": "6.6.2",
"immer": "9.0.15",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { type EdgeProps, type InternalNode, type Node, useReactFlow } from '@xyflow/react';
import { type EdgeProps, useInternalNode } from '@xyflow/react';
import type { Handle } from '@xyflow/system';
import { NodeIds } from '../../../../constants/ReactFlowConstants';
import { addSourceReactFlowPrefix, addTargetReactFlowPrefix, getTreeNodeId, isFunctionNode } from '../../../../utils/ReactFlow.Util';
import { useEffect, useMemo, useState } from 'react';
import type { RootState } from '../../../../core/state/Store';
import { useSelector } from 'react-redux';
import { flattenSchemaNode } from '../../../../utils';
import type { SchemaNodeExtended } from '@microsoft/logic-apps-shared';
import type { HandlePosition, SchemaTreeDataProps } from '../../../../core/state/DataMapSlice';
import { equals, type SchemaNodeExtended } from '@microsoft/logic-apps-shared';
import type { SchemaTreeDataProps } from '../../../../core/state/DataMapSlice';

// Return [x, y] coordinates for the handle along with the scenario of the handle,
// Scenario can be one of 'direct' (straight connection), or 'collpased' (parent is collapsed, at any level) or 'scroll' (handle scrolled out of view)
Expand All @@ -17,29 +18,36 @@ const getCoordinatesForHandle = (
schema: SchemaNodeExtended[],
openKeys: Record<string, boolean>,
createReactFlowKey: (key: string) => string,
handlePositionFromStore: Record<string, HandlePosition>,
treeData?: SchemaTreeDataProps,
node?: InternalNode<Node>,
nodeX?: number,
nodeY?: number,
handleBounds?: Handle[],
handleId?: string
): [number | undefined, number | undefined, string | undefined] => {
// If the node is a function node, return the current x and y coordinates
if (isFunctionNode(nodeId)) {
return [currentX, currentY, 'direct'];
}

const reactflowHandles = node?.internals.handleBounds?.source ?? node?.internals.handleBounds?.target ?? [];

if (handleId && node?.internals.positionAbsolute && treeData && treeData.startIndex > -1 && treeData.endIndex > -1) {
if (
handleId &&
nodeX !== undefined &&
nodeY !== undefined &&
handleBounds !== undefined &&
treeData &&
treeData.startIndex > -1 &&
treeData.endIndex > -1
) {
let x: number | undefined = undefined;
let y: number | undefined = undefined;
let scenario: 'direct' | 'collapsed' | 'scroll' | undefined;
let currentHandle: HandlePosition | undefined = handlePositionFromStore[handleId];
let currentHandle = handleBounds.find((handle) => equals(handleId, handle.id ?? ''));

if (treeData.visibleNodes.find((node) => node.key === getTreeNodeId(handleId))) {
if (currentHandle && !currentHandle.hidden) {
if (currentHandle) {
// If the handle is present in the current view, return the x and y coordinates
x = currentHandle.position.x;
y = currentHandle.position.y;
x = currentHandle.x;
y = currentHandle.y;
scenario = 'direct';
}
}
Expand All @@ -56,12 +64,12 @@ const getCoordinatesForHandle = (
openKeys[path.key] === false &&
treeData.visibleNodes.find((node) => node.key === path.key)
) {
currentHandle = handlePositionFromStore[createReactFlowKey(path.key)];
currentHandle = handleBounds.find((handle) => equals(createReactFlowKey(path.key), handle.id ?? ''));
// If handle is found => Parent is collapsed and we have the dimensions for the handle
// handle.hidden is used to check if the handle is scrolled out of view or not
if (currentHandle && !currentHandle.hidden) {
x = currentHandle.position.x;
y = currentHandle.position.y;
if (currentHandle) {
x = currentHandle.x;
y = currentHandle.y;
scenario = 'collapsed';
break;
}
Expand All @@ -74,33 +82,32 @@ const getCoordinatesForHandle = (
const indexForNodeInSchema = schema.findIndex((node) => node.key === getTreeNodeId(handleId));
if (indexForNodeInSchema >= 0) {
if (indexForNodeInSchema > treeData.endIndex) {
const reactflowHandle = reactflowHandles.find((handle) => handle.id?.startsWith('bottom-'));
const reactflowHandle = handleBounds.find((handle) => handle.id?.startsWith('bottom-'));
if (reactflowHandle) {
x = reactflowHandle.x + node.internals.positionAbsolute.x;
y = reactflowHandle.y + node.internals.positionAbsolute.y;
x = reactflowHandle.x;
y = reactflowHandle.y;
scenario = 'scroll';
}
} else {
const reactflowHandle = reactflowHandles.find((handle) => handle.id?.startsWith('top-'));
const reactflowHandle = handleBounds.find((handle) => handle.id?.startsWith('top-'));
if (reactflowHandle) {
x = reactflowHandle.x + node.internals.positionAbsolute.x;
y = reactflowHandle.y + node.internals.positionAbsolute.y;
x = reactflowHandle.x;
y = reactflowHandle.y;
scenario = 'scroll';
}
}
}
}

if (x !== undefined && y !== undefined && scenario !== undefined) {
return [x + 8, y + 8, scenario];
return [x + nodeX + 8, y + nodeY + 8, scenario];
}
}
return [undefined, undefined, undefined];
};

const useEdgePath = (props: EdgeProps) => {
const { source, target, sourceX, sourceY, targetX, targetY, data } = props;
const { getInternalNode } = useReactFlow();
const [updatedSourceCoordinates, setUpdatedSourceCoordinates] = useState<{
sourceX?: number;
sourceY?: number;
Expand All @@ -121,11 +128,21 @@ const useEdgePath = (props: EdgeProps) => {
targetScenario: undefined,
});

const sourceNode = useMemo(() => getInternalNode(NodeIds.source), [getInternalNode]);
const targetNode = useMemo(() => getInternalNode(NodeIds.target), [getInternalNode]);
const sourceNode = useInternalNode(NodeIds.source);
const targetNode = useInternalNode(NodeIds.target);
const absoluteSourceNodeX = sourceNode?.internals.positionAbsolute.x;
const absoluteSourceNodeY = sourceNode?.internals.positionAbsolute.y;
// eslint-disable-next-line react-hooks/exhaustive-deps
const sourceHandleBounds = sourceNode?.internals.handleBounds?.source ?? [];

const absoluteTargetNodeX = targetNode?.internals.positionAbsolute.x;
const absoluteTargetNodeY = targetNode?.internals.positionAbsolute.y;
// eslint-disable-next-line react-hooks/exhaustive-deps
const targetHandleBounds = targetNode?.internals.handleBounds?.target ?? [];

const { sourceSchema, targetSchema, sourceOpenKeys, targetOpenKeys, handlePosition, sourceSchemaTreeData, targetSchemaTreeData } =
useSelector((state: RootState) => state.dataMap.present.curDataMapOperation);
const { sourceSchema, targetSchema, sourceOpenKeys, targetOpenKeys, sourceSchemaTreeData, targetSchemaTreeData } = useSelector(
(state: RootState) => state.dataMap.present.curDataMapOperation
);

const flattenendSourceSchema = useMemo(
() => (sourceSchema?.schemaTreeRoot ? flattenSchemaNode(sourceSchema?.schemaTreeRoot) : []),
Expand All @@ -144,9 +161,10 @@ const useEdgePath = (props: EdgeProps) => {
flattenendSourceSchema,
sourceOpenKeys,
addSourceReactFlowPrefix,
handlePosition,
sourceSchemaTreeData,
sourceNode,
absoluteSourceNodeX,
absoluteSourceNodeY,
sourceHandleBounds,
data?.sourceHandleId as string | undefined
);

Expand All @@ -164,10 +182,11 @@ const useEdgePath = (props: EdgeProps) => {
}, [
data?.sourceHandleId,
flattenendSourceSchema,
handlePosition,
sourceSchemaTreeData,
source,
sourceNode,
absoluteSourceNodeX,
absoluteSourceNodeY,
sourceHandleBounds,
sourceOpenKeys,
sourceX,
sourceY,
Expand All @@ -184,9 +203,10 @@ const useEdgePath = (props: EdgeProps) => {
flattenendTargetSchema,
targetOpenKeys,
addTargetReactFlowPrefix,
handlePosition,
targetSchemaTreeData,
targetNode,
absoluteTargetNodeX,
absoluteTargetNodeY,
targetHandleBounds,
data?.targetHandleId as string | undefined
);

Expand All @@ -206,8 +226,6 @@ const useEdgePath = (props: EdgeProps) => {
source,
target,
data,
sourceNode,
targetNode,
sourceX,
sourceY,
targetX,
Expand All @@ -216,11 +234,13 @@ const useEdgePath = (props: EdgeProps) => {
flattenendTargetSchema,
sourceOpenKeys,
targetOpenKeys,
handlePosition,
updatedTargetCoordinates.targetX,
updatedTargetCoordinates.targetY,
updatedTargetCoordinates.targetScenario,
targetSchemaTreeData,
absoluteTargetNodeX,
absoluteTargetNodeY,
targetHandleBounds,
]);

return { ...updatedSourceCoordinates, ...updatedTargetCoordinates };
Expand Down
Loading

0 comments on commit 9603d91

Please sign in to comment.