From 384d57947902e713f3b9588ba65c724cc6615352 Mon Sep 17 00:00:00 2001
From: Mohammad Torkashvand <mohammad.torkashvand@geant.org>
Date: Mon, 3 Jun 2024 18:25:42 +0200
Subject: [PATCH] added maps to the menues

---
 .env.example                         |   4 +
 components/NetworkMap/NetworkMap.tsx | 381 +++++++++++++++++++++++++++
 package-lock.json                    | 306 ++++++++++++---------
 package.json                         |  13 +-
 pages/_app.tsx                       |  25 ++
 pages/maps/index.tsx                 |  43 +++
 public/images/juniper_icon.png       | Bin 0 -> 16464 bytes
 public/images/nokia_icon.png         | Bin 0 -> 5900 bytes
 8 files changed, 641 insertions(+), 131 deletions(-)
 create mode 100644 components/NetworkMap/NetworkMap.tsx
 create mode 100644 pages/maps/index.tsx
 create mode 100644 public/images/juniper_icon.png
 create mode 100644 public/images/nokia_icon.png

diff --git a/.env.example b/.env.example
index 120c42a..933b4a6 100644
--- a/.env.example
+++ b/.env.example
@@ -17,8 +17,12 @@ NEXTAUTH_WELL_KNOWN_OVERRIDE="http://localhost:8085/auth/.well-known/openid-conf
 NEXTAUTH_AUTHORIZATION_SCOPE_OVERRIDE="openid profile"
 NEXTAUTH_URL=http://localhost:3000/api/auth
 
+# OPA Settings
 OPA_PUBLIC_BUNDLE_URL=http://localhost:8181/v1/data/opa/public-bundle
 
+#Maps Settings
+NETWORK_TOPOLOGY_API_URL="https://orchestrator.uat.gap.geant.org/api/v1/networks/topology"
+
 # docker-compose variables
 KEYCLOAK_ADMIN=admin
 KEYCLOAK_ADMIN_PASSWORD=admin
diff --git a/components/NetworkMap/NetworkMap.tsx b/components/NetworkMap/NetworkMap.tsx
new file mode 100644
index 0000000..73e058e
--- /dev/null
+++ b/components/NetworkMap/NetworkMap.tsx
@@ -0,0 +1,381 @@
+import {
+  EuiToolTip,
+  EuiSelect,
+  EuiLoadingSpinner,
+  EuiPanel,
+  EuiFormRow,
+} from '@elastic/eui';
+import cytoscape, { ElementDefinition, Core } from 'cytoscape';
+import fcose from 'cytoscape-fcose';
+import React, { useEffect, useState, useRef } from 'react';
+
+cytoscape.use(fcose);
+
+interface IptrunkSideNode {
+  subscription_instance_id: string;
+  router_fqdn: string;
+  router_access_via_ts: boolean;
+  router_lo_ipv4_address: string;
+  router_lo_ipv6_address: string;
+  router_lo_iso_address: string;
+  router_role: string;
+  vendor: string;
+  router_site: {
+    site_internal_id: string;
+    site_name: string;
+    site_city: string;
+    site_country: string;
+    site_latitude: number;
+    site_longitude: number;
+  };
+}
+
+interface Iptrunk {
+  subscription_instance_id: string;
+  iptrunk_isis_metric: string;
+  iptrunk_capacity: string;
+  iptrunk_type: string;
+  iptrunk_ipv4_network: string;
+  iptrunk_ipv6_network: string;
+  iptrunk_sides: Array<{ iptrunk_side_node: IptrunkSideNode }>;
+}
+
+export interface NetworkTopologyData {
+  iptrunks: Array<{ iptrunk: Iptrunk; insync: boolean }>;
+}
+
+export interface NetworkMapProps {
+  data: NetworkTopologyData | null;
+}
+
+interface FcoseLayoutOptions {
+  name: 'fcose';
+  quality: string;
+  nodeRepulsion: (node: cytoscape.NodeSingular) => number;
+  idealEdgeLength: (edge: cytoscape.EdgeSingular) => number;
+}
+
+const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => {
+  const [elements, setElements] = useState<ElementDefinition[]>([]);
+  const [labelType, setLabelType] = useState('iptrunkIsisMetric');
+  const [loading, setLoading] = useState(true);
+  const [tooltipContent, setTooltipContent] = useState<JSX.Element | null>(
+    null,
+  );
+  const [tooltipPosition, setTooltipPosition] = useState<{
+    x: number;
+    y: number;
+  } | null>(null);
+  const cyRef = useRef<Core | null>(null);
+
+  useEffect(() => {
+    if (data) {
+      const transformedElements = transformDataToElements(data);
+      setElements(transformedElements);
+      setLoading(false);
+    }
+  }, [data]);
+
+  useEffect(() => {
+    if (elements.length > 0) {
+      const layoutOptions: FcoseLayoutOptions = {
+        name: 'fcose',
+        quality: 'proof',
+        nodeRepulsion: () => 10000,
+        idealEdgeLength: () => 300,
+      };
+
+      const cy: Core = cytoscape({
+        container: document.getElementById('container'),
+        elements,
+        boxSelectionEnabled: false,
+        autounselectify: true,
+        minZoom: 0.25,
+        maxZoom: 4,
+        style: [
+          {
+            selector: 'node',
+            style: {
+              label: 'data(label)',
+              'background-color': '#95a5a6',
+              'font-size': '12px',
+              color: 'black',
+            },
+          },
+          {
+            selector: '.router',
+            style: {
+              width: 1,
+              height: 1,
+              'background-fit': 'contain',
+              'background-position-x': '50%',
+              'background-position-y': '50%',
+              'background-clip': 'none',
+            },
+          },
+          {
+            selector: '.nokia',
+            style: {
+              'background-image': 'url("/images/nokia_icon.png")',
+            },
+          },
+          {
+            selector: '.juniper',
+            style: {
+              'background-image': 'url("/images/juniper_icon.png")',
+            },
+          },
+          {
+            selector: 'edge',
+            style: {
+              width: 3,
+              'line-color': '#3498db',
+              'target-arrow-color': '#3498db',
+              'curve-style': 'bezier',
+              label: 'data(label)',
+              'text-rotation': 'autorotate',
+              'font-size': '10px',
+              color: '#2c3e50',
+              'text-outline-color': '#ecf0f1',
+              'text-outline-width': 3,
+            },
+          },
+          {
+            selector: 'edge[insync="true"]',
+            style: {
+              'line-color': '#2ecc71',
+            },
+          },
+          {
+            selector: 'edge[insync="false"]',
+            style: {
+              'line-color': '#e74c3c',
+            },
+          },
+          {
+            selector: '.site',
+            style: {
+              'background-opacity': 0.1,
+              'text-valign': 'top',
+              'text-halign': 'left',
+              'font-weight': 'bold',
+              'font-size': '14px',
+              'border-color': '#2980b9',
+              'border-width': 1,
+            },
+          },
+        ],
+        layout: layoutOptions,
+      });
+
+      cyRef.current = cy;
+
+      cy.on('zoom', function () {
+        updateElementStyles(cy);
+      });
+
+      cy.on('mouseover', 'node', function (event) {
+        const node = event.target;
+        const router = node.data('self');
+        if (router) {
+          const nodeInfo = (
+            <div style={{ whiteSpace: 'nowrap' }}>
+              <strong>subscription_id:</strong>{' '}
+              {router.subscription_instance_id || 'N/A'} <br />
+              <strong>router_fqdn:</strong> {router.router_fqdn || 'N/A'} <br />
+              <strong>router_access_via_ts:</strong>{' '}
+              {router.router_access_via_ts ? 'true' : 'false'} <br />
+              <strong>router_lo_ipv4_address:</strong>{' '}
+              {router.router_lo_ipv4_address || 'N/A'} <br />
+              <strong>router_lo_ipv6_address:</strong>{' '}
+              {router.router_lo_ipv6_address || 'N/A'} <br />
+              <strong>router_lo_iso_address:</strong>{' '}
+              {router.router_lo_iso_address || 'N/A'} <br />
+              <strong>router_role:</strong> {router.router_role || 'N/A'} <br />
+              <strong>vendor:</strong> {router.vendor || 'N/A'} <br />
+            </div>
+          );
+
+          setTooltipContent(nodeInfo);
+          setTooltipPosition({
+            x: event.renderedPosition.x,
+            y: event.renderedPosition.y,
+          });
+        }
+      });
+
+      cy.on('mouseout', 'node', function () {
+        setTooltipContent(null);
+        setTooltipPosition(null);
+      });
+    }
+  }, [elements]);
+
+  const handleLabelChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
+    const selectedValue = e.target.value;
+    setLabelType(selectedValue);
+    const cy = cyRef.current;
+    if (cy) {
+      cy.edges().forEach((edge) => {
+        const iptrunk = edge.data('self');
+        let label = '';
+        switch (selectedValue) {
+          case 'iptrunkCapacity':
+            label = iptrunk.iptrunk_capacity;
+            break;
+          case 'iptrunkIsisMetric':
+            label = iptrunk.iptrunk_isis_metric;
+            break;
+          case 'iptrunkType':
+            label = iptrunk.iptrunk_type;
+            break;
+          case 'iptrunkIPV4Network':
+            label = iptrunk.iptrunk_ipv4_network;
+            break;
+          case 'iptrunkIPV6Network':
+            label = iptrunk.iptrunk_ipv6_network;
+            break;
+        }
+        edge.data('label', label);
+      });
+    }
+  };
+
+  const transformDataToElements = (
+    data: NetworkTopologyData,
+  ): ElementDefinition[] => {
+    const elements: ElementDefinition[] = [];
+    const sites = new Map<string, boolean>();
+
+    data.iptrunks.forEach((trunk) => {
+      trunk.iptrunk.iptrunk_sides.forEach((side) => {
+        const siteData = side.iptrunk_side_node.router_site;
+        const siteId = `site-${siteData.site_internal_id}`;
+
+        if (!sites.has(siteId)) {
+          const { x, y } = latLongToXY(
+            siteData.site_latitude,
+            siteData.site_longitude,
+          );
+          elements.push({
+            data: {
+              id: siteId,
+              label: `${siteData.site_name} (${siteData.site_city}, ${siteData.site_country})`,
+            },
+            position: { x, y },
+            classes: ['site'],
+          });
+          sites.set(siteId, true);
+        }
+        elements.push({
+          data: {
+            id: side.iptrunk_side_node.subscription_instance_id,
+            parent: siteId,
+            label: side.iptrunk_side_node.router_fqdn,
+            self: side.iptrunk_side_node,
+          },
+          classes: ['router', side.iptrunk_side_node.vendor.toLowerCase()],
+        });
+      });
+
+      elements.push({
+        data: {
+          id: trunk.iptrunk.subscription_instance_id,
+          source:
+            trunk.iptrunk.iptrunk_sides[0].iptrunk_side_node
+              .subscription_instance_id,
+          target:
+            trunk.iptrunk.iptrunk_sides[1].iptrunk_side_node
+              .subscription_instance_id,
+          label: trunk.iptrunk.iptrunk_isis_metric,
+          insync: trunk.insync.toString(),
+          self: trunk.iptrunk,
+        },
+      });
+    });
+
+    return elements;
+  };
+
+  const latLongToXY = (
+    latitude: number,
+    longitude: number,
+  ): { x: number; y: number } => {
+    const x = (longitude + 180) * (1000 / 360);
+    const y = (90 - latitude) * (500 / 180);
+    return { x, y };
+  };
+
+  const updateElementStyles = (cy: Core) => {
+    const zoom = cy.zoom();
+
+    const baseNodeSize = 10;
+    const baseFontSize = 5;
+
+    const scaledNodeSize = baseNodeSize * zoom;
+    const scaledFontSize = baseFontSize * zoom;
+
+    cy.style()
+      .selector('node')
+      .style({
+        width: scaledNodeSize,
+        height: scaledNodeSize,
+        'font-size': scaledFontSize,
+      })
+      .update();
+  };
+
+  return (
+    <EuiPanel>
+      {loading ? (
+        <EuiLoadingSpinner size="xl" />
+      ) : (
+        <div id="container" style={{ height: '80vh', marginTop: '20px' }}></div>
+      )}
+      {tooltipContent && tooltipPosition && (
+        <div
+          style={{
+            position: 'absolute',
+            left: tooltipPosition.x + 20,
+            top: tooltipPosition.y + 20,
+            pointerEvents: 'none',
+            zIndex: 9999,
+          }}
+        >
+          <EuiToolTip position="top" display="block">
+            <div
+              style={{
+                display: 'inline-block',
+                width: '450px',
+                backgroundColor: 'white',
+                border: '1px solid #ccc',
+                padding: '10px',
+                borderRadius: '5px',
+                zIndex: 9999,
+                boxShadow: '0 0 10px rgba(0,0,0,0.2)',
+              }}
+            >
+              {tooltipContent}
+            </div>
+          </EuiToolTip>
+        </div>
+      )}
+      <EuiFormRow fullWidth>
+        <EuiSelect
+          id="labelSelector"
+          options={[
+            { value: 'iptrunkIsisMetric', text: 'Iptrunk ISIS Metric' },
+            { value: 'iptrunkCapacity', text: 'Iptrunk Capacity' },
+            { value: 'iptrunkType', text: 'Iptrunk Type' },
+            { value: 'iptrunkIPV4Network', text: 'Iptrunk IPV4 Network' },
+            { value: 'iptrunkIPV6Network', text: 'Iptrunk IPV6 Network' },
+          ]}
+          value={labelType}
+          onChange={handleLabelChange}
+        />
+      </EuiFormRow>
+    </EuiPanel>
+  );
+};
+
+export default NetworkMap;
diff --git a/package-lock.json b/package-lock.json
index 57f2d3a..6272edc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,9 @@
         "@open-policy-agent/opa-wasm": "^1.8.1",
         "@orchestrator-ui/orchestrator-ui-components": "1.20.0",
         "@reduxjs/toolkit": "^2.0.1",
+        "axios": "^1.7.2",
+        "cytoscape": "^3.29.2",
+        "cytoscape-fcose": "^2.2.0",
         "moment": "^2.29.4",
         "next": "^14.0.4",
         "next-auth": "^4.24.5",
@@ -34,8 +37,10 @@
         "@orchestrator-ui/jest-config": "*",
         "@orchestrator-ui/tsconfig": "*",
         "@testing-library/jest-dom": "^6.2.0",
+        "@types/cytoscape": "^3.21.2",
+        "@types/cytoscape-fcose": "^2.2.4",
         "@types/node": "^20.10.5",
-        "@types/react": "^18.2.45",
+        "@types/react": "^18.3.3",
         "@types/react-dom": "^18.2.18",
         "@types/react-no-ssr": "^1.1.7",
         "esbuild-jest": "^0.5.0",
@@ -2365,6 +2370,126 @@
         "node": ">= 10"
       }
     },
+    "node_modules/@next/swc-darwin-x64": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz",
+      "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-gnu": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz",
+      "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-arm64-musl": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz",
+      "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-gnu": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
+      "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-linux-x64-musl": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz",
+      "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-arm64-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz",
+      "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-ia32-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz",
+      "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==",
+      "cpu": [
+        "ia32"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@next/swc-win32-x64-msvc": {
+      "version": "14.2.3",
+      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz",
+      "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==",
+      "cpu": [
+        "x64"
+      ],
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
     "node_modules/@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -2913,6 +3038,21 @@
         "@babel/types": "^7.20.7"
       }
     },
+    "node_modules/@types/cytoscape": {
+      "version": "3.21.2",
+      "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.2.tgz",
+      "integrity": "sha512-eadSCH9hbRV9Ej93S8wact/Oe0DuQV4qlWfST/I6k4lBu6RgqI6mVFzvppcIGzWpzZRu7iyFjFhS2qW0w7KFRA==",
+      "dev": true
+    },
+    "node_modules/@types/cytoscape-fcose": {
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/@types/cytoscape-fcose/-/cytoscape-fcose-2.2.4.tgz",
+      "integrity": "sha512-QwWtnT8HI9h+DHhG5krGc1ZY0Ex+cn85MvX96ZNAjSxuXiZDnjIZW/ypVkvvubTjIY4rSdkJY1D/Nsn8NDpmAw==",
+      "dev": true,
+      "dependencies": {
+        "@types/cytoscape": "*"
+      }
+    },
     "node_modules/@types/graceful-fs": {
       "version": "4.1.9",
       "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
@@ -3076,9 +3216,9 @@
       "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
     },
     "node_modules/@types/react": {
-      "version": "18.3.2",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.2.tgz",
-      "integrity": "sha512-Btgg89dAnqD4vV7R3hlwOxgqobUQKgx3MmrQRi0yYbs/P0ym8XozIAlkqVilPqHQwXs4e9Tf63rrCgl58BcO4w==",
+      "version": "18.3.3",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
+      "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
       "dependencies": {
         "@types/prop-types": "*",
         "csstype": "^3.0.2"
@@ -3794,9 +3934,9 @@
       }
     },
     "node_modules/axios": {
-      "version": "1.6.8",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
-      "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
+      "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
       "dependencies": {
         "follow-redirects": "^1.15.6",
         "form-data": "^4.0.0",
@@ -4481,6 +4621,14 @@
       "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
       "hasInstallScript": true
     },
+    "node_modules/cose-base": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz",
+      "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==",
+      "dependencies": {
+        "layout-base": "^2.0.0"
+      }
+    },
     "node_modules/cosmiconfig": {
       "version": "7.1.0",
       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
@@ -4625,6 +4773,25 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
     },
+    "node_modules/cytoscape": {
+      "version": "3.29.2",
+      "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.29.2.tgz",
+      "integrity": "sha512-2G1ycU28Nh7OHT9rkXRLpCDP30MKH1dXJORZuBhtEhEW7pKwgPi77ImqlCWinouyE1PNepIOGZBOrE84DG7LyQ==",
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/cytoscape-fcose": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz",
+      "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==",
+      "dependencies": {
+        "cose-base": "^2.2.0"
+      },
+      "peerDependencies": {
+        "cytoscape": "^3.2.0"
+      }
+    },
     "node_modules/damerau-levenshtein": {
       "version": "1.0.8",
       "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -10388,6 +10555,11 @@
         "node": ">=0.10"
       }
     },
+    "node_modules/layout-base": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz",
+      "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="
+    },
     "node_modules/leven": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -15078,126 +15250,6 @@
         "type": "github",
         "url": "https://github.com/sponsors/wooorm"
       }
-    },
-    "node_modules/@next/swc-darwin-x64": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz",
-      "integrity": "sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-gnu": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz",
-      "integrity": "sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-arm64-musl": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz",
-      "integrity": "sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-gnu": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
-      "integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-linux-x64-musl": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz",
-      "integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-arm64-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz",
-      "integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==",
-      "cpu": [
-        "arm64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-ia32-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz",
-      "integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==",
-      "cpu": [
-        "ia32"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
-    },
-    "node_modules/@next/swc-win32-x64-msvc": {
-      "version": "14.2.3",
-      "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz",
-      "integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==",
-      "cpu": [
-        "x64"
-      ],
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">= 10"
-      }
     }
   }
 }
diff --git a/package.json b/package.json
index 0814861..3ca3cd0 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,9 @@
     "@open-policy-agent/opa-wasm": "^1.8.1",
     "@orchestrator-ui/orchestrator-ui-components": "1.20.0",
     "@reduxjs/toolkit": "^2.0.1",
+    "axios": "^1.7.2",
+    "cytoscape": "^3.29.2",
+    "cytoscape-fcose": "^2.2.0",
     "moment": "^2.29.4",
     "next": "^14.0.4",
     "next-auth": "^4.24.5",
@@ -40,16 +43,18 @@
     "@orchestrator-ui/jest-config": "*",
     "@orchestrator-ui/tsconfig": "*",
     "@testing-library/jest-dom": "^6.2.0",
+    "@types/cytoscape": "^3.21.2",
+    "@types/cytoscape-fcose": "^2.2.4",
     "@types/node": "^20.10.5",
-    "@types/react": "^18.2.45",
+    "@types/react": "^18.3.3",
     "@types/react-dom": "^18.2.18",
     "@types/react-no-ssr": "^1.1.7",
     "esbuild-jest": "^0.5.0",
+    "eslint-config-prettier": "^8.3.0",
+    "eslint-plugin-prettier": "^3.4.0",
     "husky": "^9.0.11",
-    "typescript": "^5.3.2",
     "prettier": "^2.3.2",
-    "eslint-plugin-prettier": "^3.4.0",
-    "eslint-config-prettier": "^8.3.0"
+    "typescript": "^5.3.2"
   },
   "overrides": {
     "@elastic/eui": {
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 1309870..ce0fbae 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -9,6 +9,7 @@ import { TranslationsProvider } from '@/translations/translationsProvider';
 import { EuiProvider, EuiThemeColorMode } from '@elastic/eui';
 import '@elastic/eui/dist/eui_theme_dark.min.css';
 import '@elastic/eui/dist/eui_theme_light.min.css';
+import { EuiSideNavItemType } from '@elastic/eui/src/components/side_nav/side_nav_types';
 import {
   ApiClientContextProvider,
   ColorModes,
@@ -20,11 +21,13 @@ import {
   WfoPageTemplate,
   WfoToastsList,
   defaultOrchestratorTheme,
+  WfoMenuItemLink,
 } from '@orchestrator-ui/orchestrator-ui-components';
 import { SessionProvider } from 'next-auth/react';
 import { NextAdapter } from 'next-query-params';
 import App, { AppContext, AppInitialProps, AppProps } from 'next/app';
 import Head from 'next/head';
+import { useRouter } from 'next/router';
 import React, { useEffect, useState } from 'react';
 import NoSSR from 'react-no-ssr';
 import { QueryClient, QueryClientProvider } from 'react-query';
@@ -48,6 +51,8 @@ function CustomApp({
   pageProps,
   orchestratorConfig,
 }: AppProps & AppOwnProps) {
+  const router = useRouter();
+
   const [queryClient] = useState(() => new QueryClient(queryClientConfig));
   const [themeMode, setThemeMode] = useState<EuiThemeColorMode>(
     ColorModes.LIGHT,
@@ -84,6 +89,25 @@ function CustomApp({
     return null;
   }
 
+  const addMenuItems = (
+    defaultMenuItems: EuiSideNavItemType<object>[],
+  ): EuiSideNavItemType<object>[] => [
+    ...defaultMenuItems,
+    {
+      name: 'Maps',
+      id: '10',
+      isSelected: router.pathname === '/maps',
+      href: '/maps',
+      renderItem: () => (
+        <WfoMenuItemLink
+          path={'/maps'}
+          translationString="Maps"
+          isSelected={router.pathname === '/maps'}
+        />
+      ),
+    },
+  ];
+
   return (
     <WfoErrorBoundary>
       <OrchestratorConfigProvider
@@ -113,6 +137,7 @@ function CustomApp({
                               <WfoPageTemplate
                                 getAppLogo={getAppLogo}
                                 onThemeSwitch={handleThemeSwitch}
+                                overrideMenuItems={addMenuItems}
                               >
                                 <QueryParamProvider
                                   adapter={NextAdapter}
diff --git a/pages/maps/index.tsx b/pages/maps/index.tsx
new file mode 100644
index 0000000..49ed824
--- /dev/null
+++ b/pages/maps/index.tsx
@@ -0,0 +1,43 @@
+import NetworkMap, {
+  NetworkMapProps,
+  NetworkTopologyData,
+} from '@/components/NetworkMap/NetworkMap';
+import axios from 'axios';
+import { NextPage, GetServerSideProps } from 'next';
+import Head from 'next/head';
+import React from 'react';
+
+const Maps: NextPage<NetworkMapProps> = ({ data }) => {
+  return (
+    <>
+      <Head>
+        <title>Maps</title>
+      </Head>
+      <div>
+        <NetworkMap data={data} />
+      </div>
+    </>
+  );
+};
+
+export const getServerSideProps: GetServerSideProps = async () => {
+  try {
+    const response = await axios.get(process.env.NETWORK_TOPOLOGY_API_URL!);
+    const networkTopologyData: NetworkTopologyData = response.data;
+
+    return {
+      props: {
+        networkTopologyData,
+      },
+    };
+  } catch (error) {
+    console.error('Failed to fetch data', error);
+    return {
+      props: {
+        networkTopologyData: null,
+      },
+    };
+  }
+};
+
+export default Maps;
diff --git a/public/images/juniper_icon.png b/public/images/juniper_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cd1f608c7006c42c918b17808682b171f73e88e
GIT binary patch
literal 16464
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

literal 0
HcmV?d00001

diff --git a/public/images/nokia_icon.png b/public/images/nokia_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..7f4a5010e50e457983a3ac2a7b11ed0267477a04
GIT binary patch
literal 5900
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

literal 0
HcmV?d00001

-- 
GitLab