diff --git a/packages/otelbin/src/app/og/Node.tsx b/packages/otelbin/src/app/og/Node.tsx
index 49e45269..615f8e33 100644
--- a/packages/otelbin/src/app/og/Node.tsx
+++ b/packages/otelbin/src/app/og/Node.tsx
@@ -3,12 +3,14 @@
 
 import React from "react";
 import ConnectorIcon from "../../components/assets/svg/connector.svg";
+import type { XYPosition } from "reactflow";
 
 export interface IData {
 	label: string;
 	parentNode: string;
 	type: string;
 	id: string;
+	position: XYPosition;
 }
 
 const Node = ({ data, icon, type }: { data: IData; icon: React.ReactNode; type: string }) => {
@@ -41,7 +43,14 @@ const Node = ({ data, icon, type }: { data: IData; icon: React.ReactNode; type:
 	const isConnector = data.type.includes("connectors");
 
 	return (
-		<div tw={`h-[72px] w-[110px] flex-col items-center rounded-lg my-5 mx-[10px] flex`}>
+		<div
+			style={{
+				position: "absolute",
+				top: data.position.y,
+				left: data.position.x,
+			}}
+			tw={`h-20 w-[120px] flex-col items-center rounded-lg flex`}
+		>
 			<div
 				style={customNodeHeaderStyle}
 				tw={`px-3  text-xs font-medium h-[35%] w-full flex items-center justify-center text-white
diff --git a/packages/otelbin/src/app/og/ParentNodeTag.tsx b/packages/otelbin/src/app/og/ParentNodeTag.tsx
index bc579278..eaf2ba6d 100644
--- a/packages/otelbin/src/app/og/ParentNodeTag.tsx
+++ b/packages/otelbin/src/app/og/ParentNodeTag.tsx
@@ -15,8 +15,8 @@ export default function ParentNodeTag({ tag }: { tag: string }) {
 							key={node.type}
 							style={{
 								position: "absolute",
-								top: -8,
-								left: -20,
+								top: 0,
+								left: 0,
 								display: "flex",
 								alignItems: "center",
 								backgroundColor: node.tagBackgroundColor,
diff --git a/packages/otelbin/src/app/og/ParentsNode.tsx b/packages/otelbin/src/app/og/ParentsNode.tsx
index 3a13e4e6..644acf17 100644
--- a/packages/otelbin/src/app/og/ParentsNode.tsx
+++ b/packages/otelbin/src/app/og/ParentsNode.tsx
@@ -2,23 +2,37 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import React from "react";
-import { type Node } from "reactflow";
+import type { Edge, Node } from "reactflow";
 import ParentNodeTag from "./ParentNodeTag";
-import ArrowRight from "../../components/assets/svg/move-right.svg";
 import { ReceiversNode, ProcessorsNode, ExportersNode } from "./NodeTypes";
 import { parentNodesConfig } from "~/components/react-flow/node-types/ParentsNode";
+import { drawEdges } from "../s/[id]/metadataUtils";
 
-const ParentsNode = ({ nodeData, nodes }: { nodeData: Node; nodes?: Node[] }) => {
-	const childNodes = nodes?.filter((node) => node.parentNode === nodeData.data.label);
-	const processorsNodesCount = childNodes?.filter((node) => node.type === "processorsNode").length ?? 0;
-	const nodesWidth = 110;
-	const sumOfExporterAndReceiver = 240;
-	const edgesWidth = 80;
-	const totalNodesWidth = (processorsNodesCount ?? 0) * nodesWidth + sumOfExporterAndReceiver;
-	const totalEdgeWidth = edgesWidth * (processorsNodesCount + 1);
-	const totalPaddingX = 40;
-	const maxWidth = totalNodesWidth + (processorsNodesCount + 2) * 20 + totalEdgeWidth + totalPaddingX;
+export function svgArrowHead(id?: string) {
+	return (
+		<defs>
+			<marker
+				id={`arrowhead-${id}`}
+				viewBox="0 -5 10 10"
+				refX="5"
+				refY="0"
+				markerWidth="10"
+				markerHeight="10"
+				orient="auto"
+				fill="transparent"
+				stroke="#FFFFFF"
+			>
+				<g>
+					<path d="M0,-4L7,0L0,4" strokeWidth={0.5}></path>
+					<path d="M-1,-3.5L6,0L-1,3.5" strokeWidth={0.5}></path>
+				</g>
+			</marker>
+		</defs>
+	);
+}
 
+const ParentsNode = ({ nodeData, edges, nodes }: { nodeData: Node; edges: Edge[]; nodes?: Node[] }) => {
+	const maxWidth = nodeData.data.width;
 	const receivers = nodes
 		?.filter((node) => node.type === "receiversNode")
 		.filter((receiver) => receiver.parentNode === nodeData.data.label);
@@ -29,60 +43,15 @@ const ParentsNode = ({ nodeData, nodes }: { nodeData: Node; nodes?: Node[] }) =>
 		?.filter((node) => node.type === "processorsNode")
 		.filter((processor) => processor.parentNode === nodeData.data.label);
 
-	const nodeHeight = 72;
-	const nodeTotalMargin = 40;
-
-	function calcSVGHeight(nodes?: Node[]) {
-		const nodesCount = nodes?.length ?? 0;
-		return nodesCount * (nodeHeight + nodeTotalMargin) - nodeTotalMargin;
-	}
+	const parentNodeEdges = edges.filter((edge) => {
+		const sourceParent = edge.data.sourceParent;
+		const targetParent = edge.data.targetParent;
+		if (sourceParent === targetParent && sourceParent === nodeData.data.label) {
+			return edge;
+		}
+	});
 
-	function calcSVGPath(side: string, nodes?: Node[]) {
-		const nodesCount = nodes?.length ?? 0;
-		const height = nodesCount * (nodeHeight + nodeTotalMargin) - 40;
-
-		return (
-			<svg style={{ marginBottom: "30px" }} width="80" height={calcSVGHeight(nodes)} xmlns="http://www.w3.org/2000/svg">
-				<defs>
-					<marker
-						id="arrowhead"
-						viewBox="0 -5 10 10"
-						refX="5"
-						refY="0"
-						markerWidth="10"
-						markerHeight="10"
-						orient="auto"
-						fill="transparent"
-						stroke="#FFFFFF"
-					>
-						<g>
-							<path d="M0,-4L7,0L0,4" strokeWidth={0.5}></path>
-							<path d="M-1,-3.5L6,0L-1,3.5" strokeWidth={0.5}></path>
-						</g>
-					</marker>
-				</defs>
-				{Array.isArray(nodes) &&
-					nodes?.length > 0 &&
-					nodes.map((node, idx) => (
-						<path
-							key={node.id}
-							d={
-								side === "left"
-									? `M10 ${(idx + 1) * (height / nodesCount) - 75}
-				    C 20,${(idx + 1) * (height / nodesCount) - 75},35,${height / 2 - 25}
-						 50 ${height / 2 - 25}`
-									: `M10 ${height / 2 - 25}
-						C 20,${height / 2 - 25},35,${(idx + 1) * (height / nodesCount) - 75}
-							 50 ${(idx + 1) * (height / nodesCount) - 75}`
-							}
-							stroke="#FFFFFF"
-							fill="transparent"
-							markerEnd="url(#arrowhead)"
-						/>
-					))}
-			</svg>
-		);
-	}
+	const edgesToDraw = drawEdges(parentNodeEdges, nodeData);
 
 	return (
 		<>
@@ -99,41 +68,43 @@ const ParentsNode = ({ nodeData, nodes }: { nodeData: Node; nodes?: Node[] }) =>
 								position: "relative",
 								backgroundColor: node.backgroundColor,
 								border: node.borderColor,
-								height: `${nodeData.data.height + 50}px`,
+								height: `${nodeData.data.height}px`,
 								width: maxWidth,
 							}}
-							tw="rounded-[4px] text-[10px] text-black my-3 px-5 py-2"
+							tw="rounded-[4px] text-[10px] text-black"
 						>
 							<ParentNodeTag tag={nodeData.data.label} />
-
-							<div style={{ display: "flex", justifyContent: "center" }}>
-								<div tw="flex items-center">
-									<div tw="flex flex-col justify-center">
-										{receivers?.map((receiver) => <ReceiversNode key={receiver.id} data={receiver.data} />)}
-									</div>
-									{processors?.length === 0 ? (
-										<></>
-									) : receivers?.length === 1 ? (
-										<ArrowRight />
-									) : (
-										calcSVGPath("left", receivers)
-									)}
-								</div>
-								<div tw="flex items-center">
-									<div tw="flex justify-center items-center">
-										{processors?.map((processor, idx) => (
-											<div key={processor.id} tw="flex justify-center items-center">
-												{idx > 0 ? <ArrowRight /> : <></>}
-												<ProcessorsNode data={processor.data} />
-											</div>
-										))}
-									</div>
-									{exporters?.length === 1 ? <ArrowRight /> : calcSVGPath("right", exporters)}
-									<div tw="flex flex-col justify-center">
-										{exporters?.map((exporter) => <ExportersNode key={exporter.id} data={exporter.data} />)}
-									</div>
-								</div>
-							</div>
+							{receivers?.map((receiver) => <ReceiversNode key={receiver.id} data={receiver.data} />)}
+							{processors?.map((processor) => <ProcessorsNode key={processor.id} data={processor.data} />)}
+							{exporters?.map((exporter) => <ExportersNode key={exporter.id} data={exporter.data} />)}
+							{Array.isArray(edgesToDraw) &&
+								edgesToDraw.length > 0 &&
+								edgesToDraw?.map((edge) => (
+									<svg
+										key={edge?.edge.id}
+										style={{ position: "absolute" }}
+										width={edge?.targetPosition.x}
+										height={
+											edge && edge?.targetPosition.y < edge?.sourcePosition.y
+												? edge?.sourcePosition.y
+												: edge?.targetPosition.y
+										}
+										xmlns="http://www.w3.org/2000/svg"
+									>
+										{svgArrowHead(edge?.edge.id)}
+										<path
+											key={edge?.edge.id}
+											d={`M${edge?.sourcePosition.x} ${edge?.sourcePosition.y} C ${
+												edge && edge?.sourcePosition.x + 30
+											} ${edge?.sourcePosition.y}, ${edge && edge?.targetPosition.x - 30} ${edge?.targetPosition
+												.y} ${edge?.targetPosition.x} ${edge?.targetPosition.y}
+										`}
+											stroke="#FFFFFF"
+											fill="transparent"
+											markerEnd={`url(#arrowhead-${edge?.edge.id})`}
+										/>
+									</svg>
+								))}
 						</div>
 					);
 				})}
diff --git a/packages/otelbin/src/app/s/[id]/img/route.tsx b/packages/otelbin/src/app/s/[id]/img/route.tsx
index 708d7ae0..00e96432 100644
--- a/packages/otelbin/src/app/s/[id]/img/route.tsx
+++ b/packages/otelbin/src/app/s/[id]/img/route.tsx
@@ -3,20 +3,21 @@
 
 import { ImageResponse, NextResponse, type NextRequest } from "next/server";
 import { calcNodes } from "~/components/react-flow/useClientNodes";
-import ParentsNode from "../../../og/ParentsNode";
+import ParentsNode, { svgArrowHead } from "../../../og/ParentsNode";
 import { Redis } from "@upstash/redis/nodejs";
 import { getShortLinkPersistenceKey } from "~/lib/shortLink";
 import type { IConfig } from "~/components/react-flow/dataType";
 import { editorBinding } from "~/components/monaco-editor/editorBinding";
 import JsYaml, { FAILSAFE_SCHEMA } from "js-yaml";
-import { calcScale, toUrlState } from "../metadataUtils";
+import { calcScale, drawConnectorEdges, toUrlState } from "../metadataUtils";
 import Logo from "~/components/assets/svg/otelbin_logo_white.svg";
 import { notFound } from "next/navigation";
+import { calcEdges } from "~/components/react-flow/useEdgeCreator";
+import { getLayoutedElements } from "~/components/react-flow/layout/useLayout";
 
 export const runtime = "edge";
 
 const redis = Redis.fromEnv();
-const edgeWidth = 80;
 
 export async function GET(request: NextRequest) {
 	const shortLinkId = request.nextUrl.searchParams.get("id") ?? "";
@@ -32,8 +33,19 @@ export async function GET(request: NextRequest) {
 	}
 	const { config } = toUrlState(url, [editorBinding]);
 	const jsonData = JsYaml.load(config, { schema: FAILSAFE_SCHEMA }) as IConfig;
-	const initNodes = calcNodes(jsonData, true);
-	const parentNodes = initNodes?.filter((node) => node.type === "parentNodeType");
+	const initNodes = calcNodes(jsonData);
+
+	const initEdges = calcEdges(initNodes ?? []);
+	const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(initNodes ?? [], initEdges);
+	const parentNodes = layoutedNodes?.filter((node) => node.type === "parentNodeType");
+
+	const scale = calcScale(parentNodes)?.scale;
+	const totalYOffset = calcScale(parentNodes)?.totalYOffset;
+	const totalXOffset = calcScale(parentNodes)?.totalXOffset;
+
+	const connectorEdges = layoutedEdges?.filter((edge) => edge.data.type === "connector");
+
+	const connectorEdgesToDraw = drawConnectorEdges(connectorEdges ?? [], parentNodes, totalXOffset);
 
 	return new ImageResponse(
 		(
@@ -48,9 +60,7 @@ export async function GET(request: NextRequest) {
 					backgroundColor: "#151721",
 					position: "relative",
 					backgroundImage: `url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDQwIDQwIiBmaWxsPSIjODI4MjhCIiBzdHJva2U9IiM4MjgyOEIiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBjbGFzcz0ibHVjaWRlIGx1Y2lkZS1kb3QiPjxjaXJjbGUgY3g9IjEyLjEiIGN5PSIxMi4xIiByPSIwLjUiLz48L3N2Zz4=)`,
-					backgroundSize: `${Number(calcScale(edgeWidth, initNodes)) * 20}px ${
-						Number(calcScale(edgeWidth, initNodes)) * 20
-					}px`,
+					backgroundSize: `${Number(scale) * 20}px ${Number(scale) * 20}px`,
 					backgroundRepeat: "repeat",
 					backgroundPosition: "center",
 				}}
@@ -60,16 +70,52 @@ export async function GET(request: NextRequest) {
 				</div>
 				<div
 					style={{
-						transform: `scale(${calcScale(edgeWidth, initNodes)})`,
+						transformOrigin: "center left",
+						transform: `scale(${scale})`,
 						display: "flex",
-						flexDirection: "column",
-						justifyContent: "center",
+						position: "relative",
+						width: "100%",
 					}}
 					tw="bg-transparent"
 				>
 					{parentNodes?.map((parentNode) => (
-						<ParentsNode key={parentNode.id} nodeData={parentNode} nodes={initNodes} />
+						<div
+							key={parentNode.id}
+							style={{
+								display: "flex",
+								position: "absolute",
+								top: parentNode.position.y + totalYOffset,
+								left: parentNode.position.x + totalXOffset,
+							}}
+						>
+							<ParentsNode key={parentNode.id} nodeData={parentNode} nodes={layoutedNodes} edges={layoutedEdges} />
+						</div>
 					))}
+					{Array.isArray(connectorEdgesToDraw) &&
+						connectorEdgesToDraw.length > 0 &&
+						connectorEdgesToDraw?.map((edge) => (
+							<svg
+								key={edge.edge.id}
+								style={{ position: "absolute", top: totalYOffset }}
+								width={edge.targetPosition.x}
+								height={edge.targetPosition?.y < edge.sourcePosition.y ? edge.sourcePosition.y : edge.targetPosition.y}
+								xmlns="http://www.w3.org/2000/svg"
+							>
+								{svgArrowHead(edge?.edge.id)}
+								<path
+									key={edge.edge.id}
+									d={`M${edge.sourcePosition.x} ${edge.sourcePosition.y} C ${edge.sourcePosition.x + 40} ${
+										edge.sourcePosition.y
+									}, ${edge && edge.targetPosition?.x - 40} ${edge.targetPosition.y} ${edge.targetPosition.x} ${
+										edge.targetPosition.y
+									}
+										`}
+									stroke="#FFFFFF"
+									fill="transparent"
+									markerEnd={`url(#arrowhead-${edge.edge.id})`}
+								/>
+							</svg>
+						))}
 				</div>
 			</div>
 		),
diff --git a/packages/otelbin/src/app/s/[id]/metadataUtils.test.ts b/packages/otelbin/src/app/s/[id]/metadataUtils.test.ts
index 40f2367d..3a013622 100644
--- a/packages/otelbin/src/app/s/[id]/metadataUtils.test.ts
+++ b/packages/otelbin/src/app/s/[id]/metadataUtils.test.ts
@@ -2,10 +2,17 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { describe, expect, it } from "@jest/globals";
-import { calcScale, extractComponents, sortAndDeduplicate, toUrlState } from "./metadataUtils";
+import {
+	calcScale,
+	drawConnectorEdges,
+	drawEdges,
+	extractComponents,
+	sortAndDeduplicate,
+	toUrlState,
+} from "./metadataUtils";
 import type { IConfig } from "~/components/react-flow/dataType";
-import { type Node } from "reactflow";
 import { editorBinding } from "../../../components/monaco-editor/editorBinding";
+import { type Node } from "reactflow";
 
 describe("sortAndDeduplicate", () => {
 	it("should sort and deduplicate an array of strings and return a comma separated string of components", () => {
@@ -45,99 +52,348 @@ describe("extractComponents", () => {
 	});
 });
 
-describe("calcScale", () => {
-	const edgeWidth = 10;
+describe("toUrlState", () => {
+	it("should return empty object if url hash is not provided", () => {
+		const mockUrlWithoutHash = new URL("https://otelbin.io");
+		expect(toUrlState(mockUrlWithoutHash, [])).toStrictEqual({});
+	});
 
-	const runTest = (nodes: Node[], expectedScale: string) => {
-		it("Should calculate the correct scale based on the maximum height or width of the visualization nodes to ensure they fit within the standard 1200x630 size of the generated Open Graph image.", () => {
-			const scale = calcScale(edgeWidth, nodes);
+	it("should parse hash from URL and return urlState for the provided Binding", () => {
+		const mockUrlWithHash = new URL("https://otelbin.io/#config=123");
+		const result = toUrlState(mockUrlWithHash, [editorBinding]);
+
+		expect(result).toStrictEqual({ config: 123 });
+	});
+
+	it("should parse hash from URL and return urlState for the provided Binding with distro selected condition in the URL", () => {
+		const mockUrlWithHash = new URL(
+			"https://otelbin.io/?#distro=otelcol-core~&distroVersion=v0.91.0~&config=**H_Learn_more_about_the_OpenTelemetry_Collector_"
+		);
+		const result = toUrlState(mockUrlWithHash, [editorBinding]);
+
+		expect(result).toStrictEqual({ config: "# Learn more about the OpenTelemetry Collector " });
+	});
+});
+
+describe("calcScale", () => {
+	const runTest = (parentNodes: Node[], expectedScale: string, offsetX: number, offsetY: number) => {
+		it(`Should calculate the correct scale based on the maximum height or width of the visualization pipeline parent nodes to ensure they fit within the standard 1200x630 size of the generated Open Graph image.
+		The absolute position system in Image Response base is in the middle left of the image, so we need to calculate the offset to center the image in the middle of the 1200x630 canvas.
+		`, () => {
+			const scale = calcScale(parentNodes).scale;
+			const totalXOffset = calcScale(parentNodes).totalXOffset;
+			const totalYOffset = calcScale(parentNodes).totalYOffset;
 			expect(scale).toBe(expectedScale);
+			expect(totalXOffset).toBe(offsetX);
+			expect(totalYOffset).toBe(offsetY);
 		});
 	};
 
 	runTest(
 		[
-			{ type: "parentNodeType", data: { height: 100 }, position: { x: 100, y: 200 }, id: "1" },
-			{ type: "parentNodeType", data: { height: 200 }, position: { x: 200, y: 300 }, id: "2" },
-			{ type: "processorsNode", parentNode: "metrics", data: { height: 100 }, position: { x: 200, y: 300 }, id: "3" },
-			{ type: "processorsNode", parentNode: "metrics", data: { height: 100 }, position: { x: 210, y: 220 }, id: "4" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 100 }, position: { x: 0, y: 10 }, id: "5" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 200 }, position: { x: 10, y: 20 }, id: "6" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 300 }, position: { x: 20, y: 30 }, id: "7" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 400 }, position: { x: 30, y: 40 }, id: "8" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 500 }, position: { x: 40, y: 50 }, id: "9" },
-			{ type: "processorsNode", parentNode: "logs", data: { height: 600 }, position: { x: 50, y: 60 }, id: "10" },
+			{ type: "parentNodeType", data: { height: 100, width: 300 }, position: { x: 100, y: 200 }, id: "1" },
+			{ type: "parentNodeType", data: { height: 200, width: 300 }, position: { x: 200, y: 300 }, id: "2" },
+			{ type: "parentNodeType", data: { height: 100, width: 400 }, position: { x: 200, y: 300 }, id: "3" },
+			{ type: "parentNodeType", data: { height: 100, width: 400 }, position: { x: 210, y: 220 }, id: "4" },
+			{ type: "parentNodeType", data: { height: 100, width: 500 }, position: { x: 0, y: 10 }, id: "5" },
+			{ type: "parentNodeType", data: { height: 200, width: 300 }, position: { x: 10, y: 20 }, id: "6" },
+			{ type: "parentNodeType", data: { height: 300, width: 200 }, position: { x: 20, y: 30 }, id: "7" },
+			{ type: "parentNodeType", data: { height: 400, width: 600 }, position: { x: 30, y: 40 }, id: "8" },
+			{ type: "parentNodeType", data: { height: 500, width: 400 }, position: { x: 40, y: 50 }, id: "9" },
+			{ type: "parentNodeType", data: { height: 600, width: 500 }, position: { x: 50, y: 60 }, id: "10" },
 		],
-		"0.976"
+		"0.950",
+		316.6812439261419,
+		-325
 	);
 
 	runTest(
 		[
-			{ type: "parentNodeType", data: { height: 100 }, position: { x: 70, y: 80 }, id: "1" },
-			{ type: "parentNodeType", data: { height: 200 }, position: { x: 80, y: 90 }, id: "2" },
-			{ type: "exportersNode", parentNode: "metrics", data: { height: 100 }, position: { x: 0, y: 0 }, id: "3" },
-			{ type: "receiversNode", parentNode: "logs", data: { height: 200 }, position: { x: 0, y: 0 }, id: "4" },
+			{ type: "parentNodeType", data: { height: 100, width: 500 }, position: { x: 70, y: 80 }, id: "1" },
+			{ type: "parentNodeType", data: { height: 200, width: 600 }, position: { x: 80, y: 90 }, id: "2" },
+			{ type: "parentNodeType", data: { height: 100, width: 600 }, position: { x: 0, y: 0 }, id: "3" },
+			{ type: "parentNodeType", data: { height: 200, width: 200 }, position: { x: 0, y: 0 }, id: "4" },
 		],
-		"1.270"
+		"1.729",
+		6.938775510204082,
+		-145
 	);
 
 	runTest(
 		[
-			{ type: "parentNodeType", data: { height: 100 }, position: { x: 100, y: 110 }, id: "1" },
-			{ type: "parentNodeType", data: { height: 200 }, position: { x: 110, y: 120 }, id: "2" },
-			{ type: "exportersNode", parentNode: "traces", data: { height: 100 }, position: { x: 120, y: 130 }, id: "3" },
+			{ type: "parentNodeType", data: { height: 100, width: 250 }, position: { x: 100, y: 110 }, id: "1" },
+			{ type: "parentNodeType", data: { height: 200, width: 350 }, position: { x: 110, y: 120 }, id: "2" },
+			{ type: "parentNodeType", data: { height: 100, width: 300 }, position: { x: 120, y: 130 }, id: "3" },
 			{
-				type: "connectors/exporters",
-				parentNode: "traces",
-				data: { height: 100 },
+				type: "parentNodeType",
+				data: { height: 100, width: 450 },
 				position: { x: 130, y: 140 },
 				id: "4",
 			},
-			{ type: "receiversNode", parentNode: "traces", data: { height: 100 }, position: { x: 140, y: 150 }, id: "5" },
+			{ type: "parentNodeType", data: { height: 100, width: 200 }, position: { x: 140, y: 150 }, id: "5" },
 		],
-		"1.270"
+		"2.450",
+		4.897959183673469,
+		-104.99999999999999
 	);
 
 	runTest(
-		[
-			{ type: "parentNodeType", data: { height: 100 }, position: { x: 150, y: 160 }, id: "1" },
-			{ type: "parentNodeType", data: { height: 200 }, position: { x: 160, y: 170 }, id: "2" },
-			{ type: "exportersNode", parentNode: "metrics", data: { height: 100 }, position: { x: 170, y: 180 }, id: "3" },
-			{ type: "exportersNode", parentNode: "metrics", data: { height: 100 }, position: { x: 180, y: 190 }, id: "4" },
-			{
-				type: "connectors/receivers",
-				parentNode: "metrics",
-				data: { height: 100 },
-				position: { x: 190, y: 200 },
-				id: "5",
-			},
-			{ type: "receiversNode", parentNode: "metrics", data: { height: 100 }, position: { x: 200, y: 210 }, id: "6" },
-		],
-		"1.270"
+		[{ type: "parentNodeType", data: { height: 100, width: 600 }, position: { x: 150, y: 160 }, id: "1" }],
+		"1.960",
+		6.122448979591836,
+		-50
 	);
 
-	runTest([], "1");
+	runTest([], "1", 0, 0);
 });
 
-describe("toUrlState", () => {
-	it("should return empty object if url hash is not provided", () => {
-		const mockUrlWithoutHash = new URL("https://otelbin.io");
-		expect(toUrlState(mockUrlWithoutHash, [])).toStrictEqual({});
-	});
+enum MarkerType {
+	Arrow = "arrow",
+	ArrowClosed = "arrowclosed",
+}
 
-	it("should parse hash from URL and return urlState for the provided Binding", () => {
-		const mockUrlWithHash = new URL("https://otelbin.io/#config=123");
-		const result = toUrlState(mockUrlWithHash, [editorBinding]);
+describe("drawEdges", () => {
+	it("should calculate the correct edges and add position for each edge to draw them inside each parent node", () => {
+		const parentNode = {
+			type: "parentNodeType",
+			data: {
+				height: 100,
+				width: 250,
+				childNodes: [
+					{
+						type: "receiversNode",
+						parentNode: "metrics",
+						data: { height: 100 },
+						position: { x: 200, y: 300 },
+						id: "2",
+					},
+					{
+						type: "processorsNode",
+						parentNode: "metrics",
+						data: { height: 100 },
+						position: { x: 200, y: 300 },
+						id: "3",
+					},
+					{
+						type: "processorsNode",
+						parentNode: "metrics",
+						data: { height: 100 },
+						position: { x: 210, y: 220 },
+						id: "4",
+					},
+					{ type: "exportersNode", parentNode: "metrics", data: { height: 100 }, position: { x: 0, y: 10 }, id: "5" },
+				],
+			},
+			position: { x: 100, y: 110 },
+			id: "1",
+			label: "metrics",
+		};
 
-		expect(result).toStrictEqual({ config: 123 });
+		const markerEnd = { type: MarkerType.Arrow, color: "#9CA2AB", width: 20, height: 25 };
+		const style = { stroke: "#9CA2AB" };
+
+		const edges = [
+			{
+				id: "e1",
+				source: "2",
+				target: "3",
+				type: "default",
+				markerEnd: markerEnd,
+				style: style,
+				data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+			},
+			{
+				id: "e2",
+				source: "3",
+				target: "4",
+				type: "default",
+				markerEnd: markerEnd,
+				style: style,
+				data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+			},
+			{
+				id: "e3",
+				source: "4",
+				target: "5",
+				type: "default",
+				markerEnd: markerEnd,
+				style: style,
+				data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+			},
+		];
+
+		const result = drawEdges(edges, parentNode);
+
+		expect(result).toEqual([
+			{
+				edge: {
+					id: "e1",
+					source: "2",
+					target: "3",
+					type: "default",
+					markerEnd: markerEnd,
+					style: style,
+					data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+				},
+				sourcePosition: { x: 330, y: 340 },
+				targetPosition: { x: 190, y: 340 },
+			},
+			{
+				edge: {
+					id: "e2",
+					source: "3",
+					target: "4",
+					type: "default",
+					markerEnd: markerEnd,
+					style: style,
+					data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+				},
+				sourcePosition: { x: 330, y: 340 },
+				targetPosition: { x: 200, y: 260 },
+			},
+			{
+				edge: {
+					id: "e3",
+					source: "4",
+					target: "5",
+					type: "default",
+					markerEnd: markerEnd,
+					style: style,
+					data: { type: "edge", sourceParent: "metrics", targetParent: "metrics" },
+				},
+				sourcePosition: { x: 340, y: 260 },
+				targetPosition: { x: -10, y: 50 },
+			},
+		]);
 	});
+});
 
-	it("should parse hash from URL and return urlState for the provided Binding with distro selected condition in the URL", () => {
-		const mockUrlWithHash = new URL(
-			"https://otelbin.io/?#distro=otelcol-core~&distroVersion=v0.91.0~&config=**H_Learn_more_about_the_OpenTelemetry_Collector_"
-		);
-		const result = toUrlState(mockUrlWithHash, [editorBinding]);
+describe("drawConnectorEdges", () => {
+	it("should calculate the correct connector edges and add position for each edge to draw them between parent nodes", () => {
+		const parentNodes = [
+			{
+				type: "parentNodeType",
+				data: {
+					height: 100,
+					width: 250,
+					label: "logs",
+					childNodes: [
+						{
+							type: "receiversNode",
+							parentNode: "logs",
+							data: { height: 100, type: "connectors/receivers" },
+							position: { x: 200, y: 300 },
+							id: "2",
+						},
+						{
+							type: "processorsNode",
+							parentNode: "logs",
+							data: { height: 100 },
+							position: { x: 200, y: 300 },
+							id: "3",
+						},
+						{
+							type: "processorsNode",
+							parentNode: "logs",
+							data: { height: 100 },
+							position: { x: 210, y: 220 },
+							id: "4",
+						},
+						{ type: "exportersNode", parentNode: "logs", data: { height: 100 }, position: { x: 0, y: 10 }, id: "5" },
+					],
+				},
+				position: { x: 100, y: 110 },
+				id: "1",
+				label: "logs",
+			},
+			{
+				type: "parentNodeType",
+				data: {
+					height: 200,
+					width: 400,
+					label: "metrics",
+					childNodes: [
+						{
+							type: "receiversNode",
+							parentNode: "metrics",
+							data: { height: 100 },
+							position: { x: 200, y: 300 },
+							id: "6",
+						},
+						{
+							type: "processorsNode",
+							parentNode: "metrics",
+							data: { height: 100 },
+							position: { x: 200, y: 300 },
+							id: "7",
+						},
+						{
+							type: "processorsNode",
+							parentNode: "metrics",
+							data: { height: 100 },
+							position: { x: 200, y: 300 },
+							id: "8",
+						},
+						{
+							type: "processorsNode",
+							parentNode: "metrics",
+							data: { height: 100 },
+							position: { x: 210, y: 220 },
+							id: "9",
+						},
+						{
+							type: "exportersNode",
+							parentNode: "metrics",
+							data: { height: 100 },
+							position: { x: 0, y: 10 },
+							id: "10",
+						},
+						{
+							type: "exportersNode",
+							parentNode: "metrics",
+							data: { height: 100, type: "connectors/exporters" },
+							position: { x: 0, y: 10 },
+							id: "11",
+						},
+					],
+				},
+				position: { x: 300, y: 410 },
+				id: "12",
+				label: "metrics",
+			},
+		];
 
-		expect(result).toStrictEqual({ config: "# Learn more about the OpenTelemetry Collector " });
+		const markerEnd = { type: MarkerType.Arrow, color: "#9CA2AB", width: 20, height: 25 };
+		const style = { stroke: "#9CA2AB" };
+
+		const edges = [
+			{
+				id: "ec1",
+				source: "11",
+				target: "2",
+				type: "default",
+				markerEnd: markerEnd,
+				style: style,
+				data: { type: "connector", sourcePipeline: "metrics", targetPipeline: "logs" },
+			},
+		];
+
+		const result = drawConnectorEdges(edges, parentNodes, 100);
+
+		expect(result).toEqual([
+			{
+				edge: {
+					id: "ec1",
+					source: "11",
+					target: "2",
+					type: "default",
+					markerEnd: markerEnd,
+					style: style,
+					data: { type: "connector", sourcePipeline: "metrics", targetPipeline: "logs" },
+				},
+				sourcePosition: { x: 540, y: 460 },
+				targetPosition: { x: 390, y: 450 },
+			},
+		]);
 	});
 });
diff --git a/packages/otelbin/src/app/s/[id]/metadataUtils.ts b/packages/otelbin/src/app/s/[id]/metadataUtils.ts
index 01b7a1e5..9db4f0d6 100644
--- a/packages/otelbin/src/app/s/[id]/metadataUtils.ts
+++ b/packages/otelbin/src/app/s/[id]/metadataUtils.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import type { IConfig } from "~/components/react-flow/dataType";
-import { type Node } from "reactflow";
+import { type XYPosition, type Edge, type Node } from "reactflow";
 import type { Binding } from "~/lib/urlState/binding";
 import { parseUrlState } from "../../../lib/urlState/parseUrlState";
 import type { Bindings } from "~/lib/urlState/typeMapping";
@@ -31,35 +31,29 @@ export function extractComponents(jsonData: IConfig) {
 	return components;
 }
 
-export function calcScale(edgeWidth: number, nodes?: Node[]) {
-	if (nodes?.length === 0 || !nodes) return "1";
-	const processorsCount = {} as Record<string, number>;
-	const nodesWidth = 140;
-	const parentNodesPadding = 40;
+export function calcScale(parentNodes?: Node[]) {
 	const targetHeight = 630;
 	const targetWidth = 1200;
-	const parentNodes = nodes?.filter((node) => node.type === "parentNodeType");
-	const processors = nodes?.filter((node) => node.type === "processorsNode") ?? [];
-	const processorPipelines = processors.length > 0 ? processors.map((node) => node.parentNode) : [];
-	if (processorPipelines.length > 0) {
-		processorPipelines.forEach((pipeline) => {
-			if (pipeline && pipeline in processorsCount) {
-				processorsCount[pipeline] += 1;
-			} else if (pipeline) {
-				processorsCount[pipeline] = 1;
-			}
-		});
+
+	if (parentNodes && parentNodes?.length > 0) {
+		const nodesX = parentNodes?.map((node) => node.position.x);
+		const nodesXMax = parentNodes?.map((node) => node.position.x + node.data.width);
+		const minX = Math.min(...nodesX);
+		const maxX = Math.max(...nodesXMax);
+		const nodesY = parentNodes?.map((node) => node.position.y);
+		const nodesYMax = parentNodes?.map((node) => node.position.y + node.data.height);
+		const minY = Math.min(...nodesY);
+		const maxY = Math.max(...nodesYMax);
+		const totalHeight = maxY - minY;
+		const totalWidth = maxX - minX;
+		//For add some padding multiply it by 0.98
+		const scale = Math.min(targetHeight / totalHeight, targetWidth / totalWidth) * 0.98;
+		const totalXOffset = Math.max((targetWidth - totalWidth * scale) / 2 / scale, 0);
+		const totalYOffset = -(targetHeight / 2) / scale + Math.max((targetHeight - totalHeight * scale) / 2 / scale, 0);
+		return { scale: scale.toFixed(3).toString(), totalXOffset, totalYOffset };
 	} else {
-		processorsCount["default"] = processors.length;
+		return { scale: "1", totalXOffset: 0, totalYOffset: 0 };
 	}
-	const maxProcessorPipelineCount = Math.max(...Object.values(processorsCount));
-	const nodesHeight = parentNodes?.map((node) => node.data.height) ?? [0];
-	const totalHeight = nodesHeight?.reduce((sum, height) => sum + (height + 50), 0) + 4 * 24;
-	const totalHorizontalNodesCount = maxProcessorPipelineCount + 2;
-	const totalWidth =
-		totalHorizontalNodesCount * nodesWidth + (totalHorizontalNodesCount - 1) * edgeWidth + parentNodesPadding;
-	const scale = Math.min(targetHeight / totalHeight, targetWidth / totalWidth).toFixed(3);
-	return scale.toString();
 }
 
 export function toUrlState<T extends Binding<unknown>[]>(url: URL, binds: T): Bindings<T> {
@@ -74,3 +68,54 @@ export function toUrlState<T extends Binding<unknown>[]>(url: URL, binds: T): Bi
 
 	return parseUrlState(hashSearchParams, binds);
 }
+
+const padding = 10;
+const nodeWidth = 120 + padding;
+const halfNodeHeight = 80 / 2;
+
+export function drawEdges(edges: Edge[], parentNode: Node) {
+	return edges.map((edge) => {
+		const sourceNode = parentNode.data.childNodes.find((node: Node) => node.id === edge.source);
+		const targetNode = parentNode.data.childNodes.find((node: Node) => node.id === edge.target);
+
+		if (sourceNode && targetNode) {
+			const sourcePosition: XYPosition = {
+				x: sourceNode.position.x + nodeWidth,
+				y: sourceNode.position.y + halfNodeHeight,
+			};
+			const targetPosition: XYPosition = {
+				x: targetNode.position.x - padding,
+				y: targetNode.position.y + halfNodeHeight,
+			};
+			return { edge: edge, sourcePosition: sourcePosition, targetPosition: targetPosition };
+		}
+	});
+}
+
+export function drawConnectorEdges(edges: Edge[], parentNodes: Node[], totalXOffset = 0) {
+	return edges.map((edge) => {
+		const sourceParentName = edge.data.sourcePipeline;
+		const targetParentName = edge.data.targetPipeline;
+		const sourceParent = parentNodes.find((node) => node.data.label === sourceParentName);
+		const targetParent = parentNodes.find((node) => node.data.label === targetParentName);
+		const sourceNode = sourceParent?.data.childNodes.find((node: Node) => node.id === edge.source);
+		const targetNode = targetParent?.data.childNodes.find((node: Node) => node.id === edge.target);
+
+		if (sourceNode && targetNode && sourceParent && targetParent) {
+			const sourceParentPosition = sourceParent.position;
+			const targetParentPosition = targetParent.position;
+
+			const sourcePosition: XYPosition = {
+				x: (sourceParentPosition.x ?? 0) + sourceNode.position.x + nodeWidth + padding + totalXOffset,
+				y: (sourceParentPosition.y ?? 0) + sourceNode.position.y + halfNodeHeight,
+			};
+			const targetPosition: XYPosition = {
+				x: (targetParentPosition.x ?? 0) + targetNode?.position.x - padding + totalXOffset,
+				y: (targetParentPosition.y ?? 0) + targetNode?.position.y + halfNodeHeight,
+			};
+			return { edge: edge, sourcePosition: sourcePosition, targetPosition: targetPosition };
+		} else {
+			return { edge: edge, sourcePosition: { x: 0, y: 0 }, targetPosition: { x: 0, y: 0 } };
+		}
+	});
+}
diff --git a/packages/otelbin/src/components/assets/svg/move-right.svg b/packages/otelbin/src/components/assets/svg/move-right.svg
deleted file mode 100644
index 24f51b9b..00000000
--- a/packages/otelbin/src/components/assets/svg/move-right.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="80" height="24" viewBox="0 0 24 24" fill="none" stroke="#FFFFFF" stroke-width="" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-move-right"><path d="M19 8L22 12L19 16"/><path d="M2 12H22"/></svg>
\ No newline at end of file
diff --git a/packages/otelbin/src/components/react-flow/ReactFlow.tsx b/packages/otelbin/src/components/react-flow/ReactFlow.tsx
index 4cb891e3..6dd2d690 100644
--- a/packages/otelbin/src/components/react-flow/ReactFlow.tsx
+++ b/packages/otelbin/src/components/react-flow/ReactFlow.tsx
@@ -51,7 +51,6 @@ export default function Flow({
 	const initNodes = useClientNodes(jsonData);
 	const initEdges = useEdgeCreator(initNodes ?? []);
 	const { nodes: layoutedNodes, edges: layoutedEdges } = useLayout(initNodes ?? [], initEdges);
-
 	const [nodes, setNodes] = useNodesState(layoutedNodes !== undefined ? layoutedNodes : []);
 	const [edges, setEdges] = useEdgesState(layoutedEdges);
 	const widthSelector = (state: { width: number }) => state.width;
diff --git a/packages/otelbin/src/components/react-flow/layout/useLayout.ts b/packages/otelbin/src/components/react-flow/layout/useLayout.ts
index fa5258c5..fc105f73 100644
--- a/packages/otelbin/src/components/react-flow/layout/useLayout.ts
+++ b/packages/otelbin/src/components/react-flow/layout/useLayout.ts
@@ -3,9 +3,14 @@
 
 import Dagre from "@dagrejs/dagre";
 import { useMemo } from "react";
-import { type Node, type Edge, MarkerType } from "reactflow";
+import { type Node, type Edge } from "reactflow";
 import { getSimpleCycles } from "./getSimpleCycles";
 
+export enum MarkerType {
+	Arrow = "arrow",
+	ArrowClosed = "arrowclosed",
+}
+
 export const useLayout = (nodes: Node[], edges: Edge[]) => {
 	return useMemo(() => {
 		return getLayoutedElements(nodes, edges);
diff --git a/packages/otelbin/src/components/react-flow/useClientNodes.tsx b/packages/otelbin/src/components/react-flow/useClientNodes.tsx
index 8a3b7592..1019bcfe 100644
--- a/packages/otelbin/src/components/react-flow/useClientNodes.tsx
+++ b/packages/otelbin/src/components/react-flow/useClientNodes.tsx
@@ -56,69 +56,67 @@ const createNode = (pipelineName: string, parentNode: IPipeline, height: number,
 	keyTraces.forEach((traceItem) => {
 		switch (traceItem) {
 			case "processors":
-				Array.isArray(processors) &&
-					processors.length > 0 &&
-					processors.map((processor, index) => {
-						const id = `${pipelineName}-Processor-processorNode-${processor}`;
+				processors?.map((processor, index) => {
+					const id = `${pipelineName}-Processor-processorNode-${processor}`;
 
-						nodesToAdd.push({
-							id: id,
+					nodesToAdd.push({
+						id: id,
+						parentNode: pipelineName,
+						extent: "parent",
+						type: "processorsNode",
+						position: processorPosition(index, height, processors),
+						data: {
+							label: processor,
 							parentNode: pipelineName,
-							extent: "parent",
-							type: "processorsNode",
-							position: processorPosition(index, height || 100, processors),
-							data: {
-								label: processor,
-								parentNode: pipelineName,
-								type: "processors",
-								height: childNodesHeight,
-								id: id,
-							},
-							draggable: false,
-						});
+							type: "processors",
+							height: childNodesHeight,
+							id: id,
+							position: processorPosition(index, height, processors),
+						},
+						draggable: false,
 					});
+				});
 				break;
 			case "receivers":
-				Array.isArray(receivers) &&
-					receivers.length > 0 &&
-					receivers.map((receiver, index) => {
-						const isConnector = connectors && Object.keys(connectors).includes(receiver);
-
-						const id = `${pipelineName}-Receiver-receiverNode-${receiver}`;
+				receivers?.map((receiver, index) => {
+					const isConnector = connectors?.hasOwnProperty(receiver) ? "connectors/receivers" : "receivers";
+					const id = `${pipelineName}-Receiver-receiverNode-${receiver}`;
 
-						nodesToAdd.push({
-							id: id,
+					nodesToAdd.push({
+						id: id,
+						parentNode: pipelineName,
+						extent: "parent",
+						type: "receiversNode",
+						position: receiverPosition(index, height, receivers),
+						data: {
+							label: receiver,
 							parentNode: pipelineName,
-							extent: "parent",
-							type: "receiversNode",
-							position: receiverPosition(index, height || 100, receivers),
-							data: {
-								label: receiver,
-								parentNode: pipelineName,
-								type: isConnector ? "connectors/receivers" : "receivers",
-								height: childNodesHeight,
-								id: id,
-							},
-							draggable: false,
-						});
+							type: isConnector,
+							height: childNodesHeight,
+							id: id,
+							position: receiverPosition(index, height, receivers),
+						},
+						draggable: false,
 					});
+				});
 				break;
 			case "exporters":
 				exporters?.map((exporter, index) => {
-					const isConnector = connectors && Object.keys(connectors).includes(exporter);
+					const isConnector = connectors?.hasOwnProperty(exporter) ? "connectors/exporters" : "exporters";
 					const id = `${pipelineName}-exporter-exporterNode-${exporter}`;
 					nodesToAdd.push({
 						id: id,
 						parentNode: pipelineName,
 						extent: "parent",
 						type: "exportersNode",
-						position: exporterPosition(index, height || 100, exporters, processors ?? []),
+						position: exporterPosition(index, height, exporters, processors ?? []),
 						data: {
 							label: exporter,
 							parentNode: pipelineName,
-							type: isConnector ? "connectors/exporters" : "exporters",
+							type: isConnector,
 							height: childNodesHeight,
 							id: id,
+							position: exporterPosition(index, height, exporters, processors ?? []),
 						},
 						draggable: false,
 					});
@@ -133,7 +131,7 @@ export const useClientNodes = (value: IConfig) => {
 	return useMemo(() => calcNodes(value), [value]);
 };
 
-export const calcNodes = (value: IConfig, isServerSide?: boolean) => {
+export const calcNodes = (value: IConfig) => {
 	const pipelines = value?.service?.pipelines;
 	const connectors = value?.connectors;
 	if (pipelines == null) {
@@ -147,7 +145,7 @@ export const calcNodes = (value: IConfig, isServerSide?: boolean) => {
 		const exporters = pipeline.exporters?.length ?? 0;
 		const maxNodes = Math.max(receivers, exporters) ?? 1;
 		const spaceBetweenParents = 40;
-		const spaceBetweenNodes = isServerSide ? 40 : 90;
+		const spaceBetweenNodes = 90;
 		const totalSpacing = maxNodes * spaceBetweenNodes;
 		const parentHeight = totalSpacing + maxNodes * childNodesHeight;
 
@@ -160,6 +158,8 @@ export const calcNodes = (value: IConfig, isServerSide?: boolean) => {
 				parentNode: pipelineName,
 				width: 430 + 200 * (pipeline.processors?.length ?? 0),
 				height: maxNodes === 1 ? parentHeight : parentHeight + spaceBetweenParents,
+				type: "parentNodeType",
+				childNodes: createNode(pipelineName, pipeline, parentHeight + spaceBetweenParents, connectors),
 			},
 			draggable: false,
 			ariaLabel: pipelineName,
diff --git a/packages/otelbin/src/components/react-flow/useEdgeCreator.tsx b/packages/otelbin/src/components/react-flow/useEdgeCreator.tsx
index b447bd8c..3a667e0e 100644
--- a/packages/otelbin/src/components/react-flow/useEdgeCreator.tsx
+++ b/packages/otelbin/src/components/react-flow/useEdgeCreator.tsx
@@ -2,7 +2,12 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import { useMemo } from "react";
-import { MarkerType, type Edge, type Node } from "reactflow";
+import { type Edge, type Node } from "reactflow";
+
+export enum MarkerType {
+	Arrow = "arrow",
+	ArrowClosed = "arrowclosed",
+}
 
 function createEdge(sourceNode: Node, targetNode: Node): Edge {
 	const edgeId = `edge-${sourceNode.id}-${targetNode.id}`;
@@ -20,6 +25,11 @@ function createEdge(sourceNode: Node, targetNode: Node): Edge {
 		style: {
 			stroke: "#9CA2AB",
 		},
+		data: {
+			type: "edge",
+			sourceParent: sourceNode.parentNode,
+			targetParent: targetNode.parentNode,
+		},
 	};
 }
 
@@ -40,110 +50,111 @@ function createConnectorEdge(sourceNode: Node, targetNode: Node): Edge {
 			stroke: "#9CA2AB",
 		},
 		data: {
+			type: "connector",
 			sourcePipeline: sourceNode.parentNode,
 			targetPipeline: targetNode.parentNode,
 		},
 	};
 }
 
-function useEdgeCreator(nodeIdsArray: Node[]) {
-	return useMemo(() => {
-		const edges: Edge[] = [];
-
-		const calculateExportersNode = (exportersNodes: Node[], processorsNode: Node) => {
-			exportersNodes.forEach((targetNode) => {
-				if (!processorsNode || !targetNode) {
-					return;
-				}
-				const edge = createEdge(processorsNode, targetNode);
-				edges.push(edge);
-			});
-		};
-		const calculateProcessorsNode = (processorsNodes: Node[]) => {
-			for (let i = 0; i < processorsNodes.length; i++) {
-				const sourceNode = processorsNodes[i];
-				const targetNode = processorsNodes[i + 1];
-				if (!sourceNode || !targetNode) {
-					continue;
-				}
-				const edge = createEdge(sourceNode, targetNode);
-				edges.push(edge);
+export function calcEdges(nodeIdsArray: Node[]) {
+	const edges: Edge[] = [];
+
+	const calculateExportersNode = (exportersNodes: Node[], processorsNode: Node) => {
+		if (!processorsNode) {
+			return;
+		}
+
+		const newEdges = exportersNodes
+			.filter((targetNode) => targetNode !== undefined)
+			.map((targetNode) => createEdge(processorsNode, targetNode));
+
+		edges.push(...newEdges);
+	};
+
+	const calculateProcessorsNode = (processorsNodes: Node[]) => {
+		for (let i = 0; i < processorsNodes.length; i++) {
+			const sourceNode = processorsNodes[i];
+			const targetNode = processorsNodes[i + 1];
+			if (!sourceNode || !targetNode) {
+				continue;
 			}
-		};
+			const edge = createEdge(sourceNode, targetNode);
+			edges.push(edge);
+		}
+	};
 
-		const calculateReceiversNode = (
-			receiversNodes: Node[],
-			firstProcessorsNode: Node | undefined,
-			exportersNodes: Node[]
-		) => {
-			if (!firstProcessorsNode) {
-				receiversNodes.forEach((sourceNode) => {
-					if (!sourceNode) {
-						return;
-					}
-					exportersNodes.forEach((exporterNode) => {
-						if (!exporterNode) {
-							return;
-						}
-						const edge = createEdge(sourceNode, exporterNode);
-						edges.push(edge);
-					});
-				});
-			} else {
-				receiversNodes.forEach((sourceNode) => {
-					if (!sourceNode) {
-						return;
-					}
-					const edge = createEdge(sourceNode, firstProcessorsNode);
-					edges.push(edge);
-				});
+	const calculateReceiversNode = (
+		receiversNodes: Node[],
+		firstProcessorsNode: Node | undefined,
+		exportersNodes: Node[]
+	) => {
+		const processNode = (sourceNode: Node, targetNode: Node) => {
+			if (!sourceNode || !targetNode) {
+				return;
 			}
+
+			const edge = createEdge(sourceNode, targetNode);
+			edges.push(edge);
 		};
 
-		const calculateConnectorsNode = (nodes: Node[]) => {
-			const connectorsAsExporter = nodes.filter((node) => node?.data?.type === "connectors/exporters");
-			const connectorsAsReceiver = nodes.filter((node) => node?.data?.type === "connectors/receivers");
-			connectorsAsExporter.forEach((sourceNode) => {
-				connectorsAsReceiver.forEach((targetNode) => {
-					if (targetNode?.data?.label === sourceNode?.data?.label) {
-						const edge = createConnectorEdge(sourceNode, targetNode);
-						edges.push(edge);
-					}
-				});
+		if (!firstProcessorsNode) {
+			receiversNodes.forEach((sourceNode) => {
+				exportersNodes.forEach((exporterNode) => processNode(sourceNode, exporterNode));
 			});
-		};
+		} else {
+			receiversNodes.forEach((sourceNode) => processNode(sourceNode, firstProcessorsNode));
+		}
+	};
 
-		const addEdgesToNodes = (nodes: Node[]) => {
-			const exportersNodes = nodes.filter((node) => node.type === "exportersNode");
-			const processorsNodes = nodes.filter((node) => node.type === "processorsNode");
-			const receiversNodes = nodes.filter((node) => node.type === "receiversNode");
-			const firstProcessorsNode = processorsNodes[0] as Node;
-			const lastProcessorsNode = processorsNodes[processorsNodes.length - 1] as Node;
+	const calculateConnectorsNode = (nodes: Node[]) => {
+		const connectorsAsExporter = nodes.filter((node) => node?.data?.type === "connectors/exporters");
+		const connectorsAsReceiver = nodes.filter((node) => node?.data?.type === "connectors/receivers");
 
-			calculateExportersNode(exportersNodes, lastProcessorsNode);
-			calculateProcessorsNode(processorsNodes);
-			calculateReceiversNode(receiversNodes, firstProcessorsNode, exportersNodes);
-		};
+		connectorsAsExporter.forEach((sourceNode) => {
+			const targetNode = connectorsAsReceiver.find((node) => node?.data?.label === sourceNode?.data?.label);
 
-		const childNodes = (parentNode: string) => {
-			return nodeIdsArray.filter((node) => node.parentNode === parentNode);
-		};
+			if (targetNode) {
+				edges.push(createConnectorEdge(sourceNode, targetNode));
+			}
+		});
+	};
 
-		const parentNodes = nodeIdsArray.filter((node) => node.type === "parentNodeType").map((node) => node.data.label);
-		if (!Array.isArray(nodeIdsArray) || nodeIdsArray.length < 2) {
-			return [];
-		}
+	const addEdgesToNodes = (nodes: Node[]) => {
+		const exportersNodes = nodes.filter((node) => node.type === "exportersNode");
+		const processorsNodes = nodes.filter((node) => node.type === "processorsNode");
+		const receiversNodes = nodes.filter((node) => node.type === "receiversNode");
+		const firstProcessorsNode = processorsNodes[0] as Node;
+		const lastProcessorsNode = processorsNodes[processorsNodes.length - 1] as Node;
 
-		parentNodes.forEach((parentNode) => {
-			const childNode = childNodes(parentNode);
-			addEdgesToNodes(childNode);
-		});
+		calculateExportersNode(exportersNodes, lastProcessorsNode);
+		calculateProcessorsNode(processorsNodes);
+		calculateReceiversNode(receiversNodes, firstProcessorsNode, exportersNodes);
+	};
+
+	const childNodes = (parentNode: string) => {
+		return nodeIdsArray.filter((node) => node.parentNode === parentNode);
+	};
+
+	const parentNodes = nodeIdsArray.filter((node) => node.type === "parentNodeType").map((node) => node.data.label);
+	if (!Array.isArray(nodeIdsArray) || nodeIdsArray.length < 2) {
+		return [];
+	}
 
-		calculateConnectorsNode(
-			nodeIdsArray.filter((node) => node.type === "exportersNode" || node.type === "receiversNode")
-		);
+	parentNodes.forEach((parentNode) => {
+		const childNode = childNodes(parentNode);
+		addEdgesToNodes(childNode);
+	});
 
-		return edges;
+	calculateConnectorsNode(
+		nodeIdsArray.filter((node) => node.type === "exportersNode" || node.type === "receiversNode")
+	);
+
+	return edges;
+}
+function useEdgeCreator(nodeIdsArray: Node[]) {
+	return useMemo(() => {
+		return calcEdges(nodeIdsArray);
 	}, [nodeIdsArray]);
 }