Skip to content

Commit

Permalink
fix react flow slowness due to css and and add switch to orientation …
Browse files Browse the repository at this point in the history
…button
  • Loading branch information
florianbgt committed Oct 28, 2024
1 parent 59bdb2d commit 034eff4
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 94 deletions.
51 changes: 42 additions & 9 deletions packages/app/src/components/ApiTree/ApiTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ export default function ApiTree(props: {

const reactFlow = useReactFlow();

const [currentZoom, setCurrentZoom] = useState<number>(reactFlow.getZoom());

const [nodes, setNodes, onNodesChange] = useNodesState<Node>([]);
const [edges, setEdges] = useEdgesState<Edge>([]);

const [direction, setDirection] = useState<"TB" | "LR">("TB");

useEffect(() => {
computeNodesAndEdgesFromEndpoints(props.endpoints);
}, [props.endpoints]);
Expand Down Expand Up @@ -162,28 +162,31 @@ export default function ApiTree(props: {
const { nodes: layoutedNodes, edges: layoutedEdges } = layoutNodesAndEdges(
newNodes,
newEdges,
direction,
);

setNodes(layoutedNodes);
setEdges(layoutedEdges);
}

function handleReposition() {
function handleReposition(direction: "TB" | "LR") {
const { nodes: layoutedNodes, edges: layoutedEdges } = layoutNodesAndEdges(
nodes,
edges,
direction,
);
setNodes(layoutedNodes);
setEdges(layoutedEdges);
}

function handleFitView() {
reactFlow.fitView();
updateZoom();
}

function updateZoom() {
setCurrentZoom(reactFlow.getZoom());
function handleChangeDirection() {
const newDirection = direction === "TB" ? "LR" : "TB";
setDirection(newDirection);
handleReposition(newDirection);
}

useEffect(() => {
Expand All @@ -201,7 +204,6 @@ export default function ApiTree(props: {
edges={edges}
onNodesChange={onNodesChange}
fitView
onViewportChange={updateZoom}
>
<div className="absolute bottom-6 inset-x-4 z-10 flex justify-around">
<div className="flex gap-3 items-center">
Expand Down Expand Up @@ -264,7 +266,7 @@ export default function ApiTree(props: {
variant="ghost"
highContrast
disabled={props.busy}
onClick={handleReposition}
onClick={() => handleReposition(direction)}
>
<svg
width="20"
Expand All @@ -277,6 +279,38 @@ export default function ApiTree(props: {
<path d="M15 3c.552 0 1 .448 1 1v4c0 .552-.448 1-1 1h-2v2h4c.552 0 1 .448 1 1v3h2c.552 0 1 .448 1 1v4c0 .552-.448 1-1 1h-6c-.552 0-1-.448-1-1v-4c0-.552.448-1 1-1h2v-2H8v2h2c.552 0 1 .448 1 1v4c0 .552-.448 1-1 1H4c-.552 0-1-.448-1-1v-4c0-.552.448-1 1-1h2v-3c0-.552.448-1 1-1h4V9H9c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zM9 17H5v2h4v-2zm10 0h-4v2h4v-2zM14 5h-4v2h4V5z"></path>{" "}
</svg>
</Button>
<Button
size="1"
variant="ghost"
highContrast
disabled={props.busy}
onClick={handleChangeDirection}
>
<svg
width="20"
height="20"
viewBox="10 10 80 80"
xmlns="http://www.w3.org/2000/svg"
className="text-text-light dark:text-text-dark"
>
<rect
x="20"
y="40"
width="40"
height="30"
stroke="currentColor"
stroke-width="7"
/>
<rect
x="45"
y="15"
width="30"
height="40"
stroke="currentColor"
stroke-width="7"
/>
</svg>
</Button>
<Button
size="1"
variant="ghost"
Expand All @@ -296,7 +330,6 @@ export default function ApiTree(props: {
<path d="M10.8333 7.5H5.83333C5.61232 7.5 5.40036 7.5878 5.24408 7.74408C5.0878 7.90036 5 8.11232 5 8.33333C5 8.55435 5.0878 8.76631 5.24408 8.92259C5.40036 9.07887 5.61232 9.16667 5.83333 9.16667H10.8333C11.0543 9.16667 11.2663 9.07887 11.4226 8.92259C11.5789 8.76631 11.6667 8.55435 11.6667 8.33333C11.6667 8.11232 11.5789 7.90036 11.4226 7.74408C11.2663 7.5878 11.0543 7.5 10.8333 7.5Z" />
</svg>
</Button>
<div>{(currentZoom * 100).toFixed(0)}%</div>
<Button
size="1"
variant="ghost"
Expand Down
94 changes: 46 additions & 48 deletions packages/app/src/components/ApiTree/EndpointNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import { DataList } from "@radix-ui/themes";
import EndpointNodeContentDialog from "./EndpointNodeContentDialog";
import MethodBadge from "../MethodBadge";
import GroupBadge from "../GroupBadge";
import { memo } from "react";

export default memo(function EndpointNode(
export default function EndpointNode(
props: NodeProps<
Node<{
busy: boolean;
Expand All @@ -17,58 +16,57 @@ export default memo(function EndpointNode(
>,
) {
return (
<>
<div className="backdrop-blur-sm bg-[#FFFFFF1A] rounded-xl border border-border-light dark:border-border-dark overflow-hidden">
<Handle
type="target"
position={Position.Top}
className="border border-gray-dark"
<div className="bg-secondarySurface-light dark:bg-secondarySurface-dark rounded-xl border border-border-light dark:border-border-dark overflow-hidden">
<Handle
type="target"
position={props.targetPosition || Position.Top}
isConnectable={props.isConnectable}
className="border border-gray-dark"
/>
<div
className="h-[5px]"
style={{ backgroundColor: props.data.groupColor }}
/>
<div className="bg-background-light dark:bg-background-dark px-5 py-1 flex justify-between items-center">
<div>Action</div>
<EndpointNodeContentDialog
busy={props.data.busy}
endpoint={props.data.endpoint}
onChangeGroup={props.data.onChangeGroup}
/>
<div
className="h-[5px]"
style={{ backgroundColor: props.data.groupColor }}
/>
<div className="bg-background-light dark:bg-background-dark px-5 py-1 flex justify-between items-center">
<div>Action</div>
<EndpointNodeContentDialog
busy={props.data.busy}
endpoint={props.data.endpoint}
onChangeGroup={props.data.onChangeGroup}
/>
</div>
<div className="px-5 py-3">
<DataList.Root>
<DataList.Item>
<DataList.Label className="text-text-light dark:text-text-dark">
Method
</DataList.Label>
<DataList.Value>
<MethodBadge method={props.data.endpoint.method} />
</DataList.Value>
</DataList.Item>
</div>
<div className="px-5 py-3">
<DataList.Root>
<DataList.Item>
<DataList.Label className="text-text-light dark:text-text-dark">
Method
</DataList.Label>
<DataList.Value>
<MethodBadge method={props.data.endpoint.method} />
</DataList.Value>
</DataList.Item>
<DataList.Item>
<DataList.Label className="text-text-light dark:text-text-dark">
Path
</DataList.Label>
<DataList.Value>
<div className="text-text-light dark:text-text-dark">
{props.data.endpoint.path}
</div>
</DataList.Value>
</DataList.Item>
{props.data.endpoint.group && (
<DataList.Item>
<DataList.Label className="text-text-light dark:text-text-dark">
Path
Group
</DataList.Label>
<DataList.Value>
<div className="text-text-light dark:text-text-dark">
{props.data.endpoint.path}
</div>
<GroupBadge name={props.data.endpoint.group} />
</DataList.Value>
</DataList.Item>
{props.data.endpoint.group && (
<DataList.Item>
<DataList.Label className="text-text-light dark:text-text-dark">
Group
</DataList.Label>
<DataList.Value>
<GroupBadge name={props.data.endpoint.group} />
</DataList.Value>
</DataList.Item>
)}
</DataList.Root>
</div>
)}
</DataList.Root>
</div>
</>
</div>
);
});
}
37 changes: 17 additions & 20 deletions packages/app/src/components/ApiTree/GroupNode.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import { Handle, Node, NodeProps, Position } from "@xyflow/react";
import { memo } from "react";

export default memo(function GroupNode(
props: NodeProps<Node<{ path: string }>>,
) {
export default function GroupNode(props: NodeProps<Node<{ path: string }>>) {
return (
<>
<div className="backdrop-blur-sm bg-[#FFFFFF1A] rounded-xl border border-border-light dark:border-border-dark">
<Handle
type="target"
position={Position.Top}
className="border border-gray-light dark:border-gray-dark"
/>
<div className="text-center font-bold p-5">/{props.data.path}</div>
<Handle
type="source"
position={Position.Bottom}
className="border border-gray-light dark:border-gray-dark"
/>
</div>
</>
<div className="bg-secondarySurface-light dark:bg-secondarySurface-dark rounded-xl border border-border-light dark:border-border-dark">
<Handle
type="target"
position={props.targetPosition || Position.Top}
isConnectable={props.isConnectable}
className="border border-gray-light dark:border-gray-dark"
/>
<div className="text-center font-bold p-5">/{props.data.path}</div>
<Handle
type="source"
position={props.sourcePosition || Position.Bottom}
isConnectable={props.isConnectable}
className="border border-gray-light dark:border-gray-dark"
/>
</div>
);
});
}
40 changes: 24 additions & 16 deletions packages/app/src/service/dagree.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
import { Node, Edge, Position } from "@xyflow/react";
import dagre from "@dagrejs/dagre";

function getNodeHeight(node: Node) {
if (node.type === "groupNode") {
return 100;
}
if (node.type === "endpointNode") {
return 200;
function getNodeHeight(node: Node, isHorizontal: boolean) {
if (isHorizontal) {
if (node.type === "groupNode") {
return 100;
}
if (node.type === "endpointNode") {
return 200;
}
}
return 100;
}

export function layoutNodesAndEdges(nodes: Node[], edges: Edge[]) {
const nodeWidth = 300;

const direction = "TB";
function getNodeWidth(isHorizontal: boolean) {
if (isHorizontal) {
return 350;
}
return 300;
}

export function layoutNodesAndEdges(
nodes: Node[],
edges: Edge[],
direction: "LR" | "TB",
) {
const dagreGraph = new dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));

// @ts-expect-error ignore ts(2367)
const isHorizontal = direction === "LR";
dagreGraph.setGraph({ rankdir: direction });

nodes.forEach((node) => {
dagreGraph.setNode(node.id, {
width: nodeWidth,
height: getNodeHeight(node),
width: getNodeWidth(isHorizontal),
height: getNodeHeight(node, isHorizontal),
});
});

Expand All @@ -45,10 +53,10 @@ export function layoutNodesAndEdges(nodes: Node[], edges: Edge[]) {
: ("bottom" as Position),
// We are shifting the dagre node position (anchor=center center) to the top left
// so it matches the React Flow node anchor point (top left).
width: nodeWidth,
width: 300,
position: {
x: nodeWithPosition.x - nodeWidth / 2,
y: nodeWithPosition.y - getNodeHeight(node) / 2,
x: nodeWithPosition.x - getNodeWidth(isHorizontal) / 2,
y: nodeWithPosition.y - getNodeHeight(node, isHorizontal) / 2,
},
};

Expand Down
2 changes: 1 addition & 1 deletion packages/app/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default {
},
secondarySurface: {
dark: "#25235C",
light: "#D1D5DB",
light: "#F0F1F3",
},
border: {
dark: "#3A397C",
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

Fix performance issue with reactflow due to blur background css
add support for orientation switch of the graph (portrait/landscape)

## [0.0.11] - 2024-10-28

improve CI
Expand Down

0 comments on commit 034eff4

Please sign in to comment.