diff --git a/components/NetworkMap/NetworkMap.tsx b/components/NetworkMap/NetworkMap.tsx index 842f978ae5a6bb4daa90f356044371e1f631364b..bd4818869efa657ce6e730d712ab68bfb08eb276 100644 --- a/components/NetworkMap/NetworkMap.tsx +++ b/components/NetworkMap/NetworkMap.tsx @@ -1,11 +1,5 @@ import { NetworkTopologyData } from '@/types/types'; -import { - EuiToolTip, - EuiSelect, - EuiLoadingSpinner, - EuiPanel, - EuiFormRow, -} from '@elastic/eui'; +import { EuiToolTip, EuiSelect, EuiPanel, EuiFormRow } from '@elastic/eui'; import cytoscape, { ElementDefinition, Core } from 'cytoscape'; import fcose from 'cytoscape-fcose'; import React, { useEffect, useState, useRef } from 'react'; @@ -26,7 +20,6 @@ interface FcoseLayoutOptions { 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, ); @@ -40,7 +33,6 @@ const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => { if (data) { const transformedElements = transformDataToElements(data); setElements(transformedElements); - setLoading(false); } }, [data]); @@ -295,11 +287,7 @@ const NetworkMap: React.FC<NetworkMapProps> = ({ data }) => { return ( <EuiPanel> - {loading ? ( - <EuiLoadingSpinner size="xl" /> - ) : ( - <div id="container" style={{ height: '80vh', marginTop: '20px' }}></div> - )} + <div id="container" style={{ height: '80vh', marginTop: '20px' }}></div> {tooltipContent && tooltipPosition && ( <div style={{ diff --git a/contexts/GsoConfigContext.tsx b/contexts/GsoConfigContext.tsx index c2dee34bdd8ae22b94a7af6219b5079442454d5b..0196a72d4af07924e51bc4d28ab3dc0276c862f3 100644 --- a/contexts/GsoConfigContext.tsx +++ b/contexts/GsoConfigContext.tsx @@ -3,6 +3,7 @@ import React, { createContext, useContext, ReactNode } from 'react'; export interface GsoConfig { opaPublicBundleUrl: string; oidcClientId: string; + networkTopologyApiUrl: string; } const GsoConfigContext = createContext<GsoConfig | undefined>(undefined); diff --git a/pages/api/runtime-config.ts b/pages/api/runtime-config.ts index ca8e6c91cecd3e0f2ab68c8fc849755949027642..00df94451c6d4b52c2d7efca0074ebaff6b9e478 100644 --- a/pages/api/runtime-config.ts +++ b/pages/api/runtime-config.ts @@ -3,6 +3,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; interface RuntimeConfig { opaPublicBundleUrl: string; oidcClientId: string; + networkTopologyApiUrl: string; } export default async function handler( @@ -12,6 +13,7 @@ export default async function handler( const config: RuntimeConfig = { opaPublicBundleUrl: process.env.OPA_PUBLIC_BUNDLE_URL || '', oidcClientId: process.env.NEXTAUTH_CLIENT_ID || '', + networkTopologyApiUrl: process.env.NETWORK_TOPOLOGY_API_URL || '', }; res.status(200).json(config); diff --git a/pages/maps/index.tsx b/pages/maps/index.tsx index 958b212330014c8200296f1023d2d6d4ea083bc2..b76d9674a22a55553762af2809f398a4b6128162 100644 --- a/pages/maps/index.tsx +++ b/pages/maps/index.tsx @@ -1,45 +1,67 @@ import NetworkMap from '@/components/NetworkMap/NetworkMap'; +import { useGsoConfig } from '@/contexts/GsoConfigContext'; import { GSOPolicyResource } from '@/types/policyResources'; import { NetworkTopologyData } from '@/types/types'; -import { WfoPolicyRenderPageFallback } from '@orchestrator-ui/orchestrator-ui-components'; +import { EuiLoadingSpinner, EuiText } from '@elastic/eui'; +import { + useWfoSession, + WfoPolicyRenderPageFallback, +} from '@orchestrator-ui/orchestrator-ui-components'; import axios from 'axios'; -import { NextPage, GetServerSideProps } from 'next'; -import React from 'react'; +import React, { useEffect, useState } from 'react'; -interface MapsProps { - networkTopologyData: NetworkTopologyData; -} +const MapsPage: React.FC = () => { + const [networkTopologyData, setNetworkTopologyData] = + useState<NetworkTopologyData | null>(null); + const [loading, setLoading] = useState<boolean>(true); + const [error, setError] = useState<boolean>(false); + const TIMEOUT = 5000; + const config = useGsoConfig(); + const { session } = useWfoSession(); -const AXIOS_TIMEOUT = 10000; // 10 seconds + useEffect(() => { + const fetchData = async () => { + try { + const requestHeaders = { + Authorization: session ? `Bearer ${session.accessToken}` : '', + }; + const response = await axios.get<NetworkTopologyData>( + config.networkTopologyApiUrl!, + { + timeout: TIMEOUT, + headers: requestHeaders, + }, + ); + setNetworkTopologyData(response.data); + setLoading(false); + } catch (error) { + console.error('Failed to fetch data', error); + setError(true); + setLoading(false); + } + }; + + if (session) { + fetchData(); + } else { + setLoading(false); + setError(true); + } + }, [session]); -const MapsPage: NextPage<MapsProps> = ({ networkTopologyData }) => { return ( <WfoPolicyRenderPageFallback resource={GSOPolicyResource.NAVIGATION_MAPS}> - <NetworkMap data={networkTopologyData} /> + {loading ? ( + <EuiLoadingSpinner size="xl" /> + ) : error ? ( + <EuiText color="danger"> + Failed to load data. Please try again later. + </EuiText> + ) : ( + <NetworkMap data={networkTopologyData} /> + )} </WfoPolicyRenderPageFallback> ); }; -export const getServerSideProps: GetServerSideProps = async () => { - try { - const response = await axios.get(process.env.NETWORK_TOPOLOGY_API_URL!, { - timeout: AXIOS_TIMEOUT, - }); - const networkTopologyData: NetworkTopologyData = response.data; - - return { - props: { - networkTopologyData, - }, - }; - } catch (error) { - console.error('Failed to fetch data', error); - return { - props: { - networkTopologyData: null, - }, - }; - } -}; - export default MapsPage;