diff --git a/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraph.tsx b/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraph.tsx index 2fb3406b217b2..cb3694f896426 100644 --- a/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraph.tsx +++ b/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraph.tsx @@ -26,6 +26,7 @@ import CidrBlockSideBar from './cidr/CidrBlockSideBar'; import ExternalEntitiesSideBar from './external/ExternalEntitiesSideBar'; import './Topology.css'; +import { getNodeById } from './utils/networkGraphUtils'; // TODO: move these type defs to a central location export const UrlDetailType = { @@ -38,11 +39,6 @@ export const UrlDetailType = { export type UrlDetailTypeKey = keyof typeof UrlDetailType; export type UrlDetailTypeValue = typeof UrlDetailType[UrlDetailTypeKey]; -function findEntityById(graphModel: Model, id: string | undefined): NodeModel | undefined { - const entity = graphModel.nodes?.find((node: { id: string }) => node.id === id); - return entity; -} - function getUrlParamsForEntity(selectedEntity: NodeModel): [UrlDetailTypeValue, string] { const detailType = UrlDetailType[selectedEntity.data.type]; const detailId = selectedEntity.id; @@ -95,7 +91,7 @@ function setEdges(controller, detailId) { const TopologyComponent = ({ model }: TopologyComponentProps) => { const history = useHistory(); const { detailId } = useParams(); - const selectedEntity = detailId && findEntityById(model, detailId); + const selectedEntity = detailId && getNodeById(model, detailId); const controller = useVisualizationController(); // to prevent error where graph hasn't initialized yet @@ -109,7 +105,7 @@ const TopologyComponent = ({ model }: TopologyComponentProps) => { function onSelect(ids: string[]) { const newSelectedId = ids?.[0] || ''; - const newSelectedEntity = findEntityById(model, newSelectedId); + const newSelectedEntity = getNodeById(model, newSelectedId); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore if (newSelectedEntity) { @@ -132,6 +128,7 @@ const TopologyComponent = ({ model }: TopologyComponentProps) => { return () => { controller.removeEventListener(SELECTION_EVENT, onSelect); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [controller, model]); const selectedIds = selectedEntity ? [selectedEntity.id] : []; @@ -144,7 +141,11 @@ const TopologyComponent = ({ model }: TopologyComponentProps) => { )} {selectedEntity && selectedEntity?.data?.type === 'DEPLOYMENT' && ( - + )} {selectedEntity && selectedEntity?.data?.type === 'CIDR_BLOCK' && ( diff --git a/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraphPage.tsx b/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraphPage.tsx index 6a81bdb3e490d..f04219e02b62e 100644 --- a/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraphPage.tsx +++ b/ui/apps/platform/src/Containers/NetworkGraph/NetworkGraphPage.tsx @@ -7,7 +7,7 @@ import { fetchClustersAsArray, Cluster } from 'services/ClustersService'; import PageTitle from 'Components/PageTitle'; import NetworkGraph from './NetworkGraph'; -import { transformData, graphModel } from './utils'; +import { transformData, graphModel } from './utils/modelUtils'; import './NetworkGraphPage.css'; diff --git a/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentDetails.tsx b/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentDetails.tsx index 0f384f6fb81d0..acec599fdf362 100644 --- a/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentDetails.tsx +++ b/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentDetails.tsx @@ -18,6 +18,18 @@ import { TextVariants, } from '@patternfly/react-core'; import { ExclamationCircleIcon } from '@patternfly/react-icons'; +import pluralize from 'pluralize'; + +import { Deployment } from 'types/deployment.proto'; +import { ListenPort } from 'types/networkFlow.proto'; +import { getDateTime } from 'utils/dateUtils'; + +type DeploymentDetailsProps = { + deployment: Deployment; + numExternalFlows: number; + numInternalFlows: number; + listenPorts: ListenPort[]; +}; function DetailSection({ title, children }) { const [isExpanded, setIsExpanded] = useState(true); @@ -43,7 +55,12 @@ function DetailSection({ title, children }) { ); } -function DeploymentDetails() { +function DeploymentDetails({ + deployment, + numExternalFlows, + numInternalFlows, + listenPorts, +}: DeploymentDetailsProps) { return (
    @@ -63,7 +80,8 @@ function DeploymentDetails() { color="red" icon={} > - 2 external flows + {numExternalFlows} external{' '} + {pluralize('flow', numExternalFlows)} @@ -72,7 +90,8 @@ function DeploymentDetails() { color="gold" icon={} > - 3 internal flows + {numInternalFlows} internal{' '} + {pluralize('flow', numInternalFlows)} @@ -110,7 +129,19 @@ function DeploymentDetails() { alignItems={{ default: 'alignItemsCenter' }} > - + + {listenPorts.map(({ port, l4protocol }) => { + const protocol = l4protocol.replace( + 'L4_PROTOCOL_', + '' + ); + return ( + + ); + })} + @@ -128,21 +159,21 @@ function DeploymentDetails() { Name Created - 12/09/21 | 6:03:23 PM + {getDateTime(deployment.created)} Cluster @@ -150,7 +181,7 @@ function DeploymentDetails() { Namespace @@ -158,7 +189,7 @@ function DeploymentDetails() { Replicas @@ -166,7 +197,7 @@ function DeploymentDetails() { Service account @@ -178,10 +209,15 @@ function DeploymentDetails() { Labels - - + {Object.keys(deployment.labels).map((labelKey) => { + const labelValue = deployment.labels[labelKey]; + const label = `${labelKey}:${labelValue}`; + return ( + + ); + })} @@ -189,33 +225,23 @@ function DeploymentDetails() { Annotations - - + {Object.keys(deployment.annotations).map( + (annotationKey) => { + const annotationValue = + deployment.annotations[annotationKey]; + const annotation = `${annotationKey}:${annotationValue}`; + return ( + + ); + } + )} - - - - AddCapabilities - - SYS_ADMIN - - - - Privileged - - true - - - - diff --git a/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentSideBar.tsx b/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentSideBar.tsx index e84b365359693..0aeee27bf3f22 100644 --- a/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentSideBar.tsx +++ b/ui/apps/platform/src/Containers/NetworkGraph/deployment/DeploymentSideBar.tsx @@ -1,8 +1,12 @@ import React from 'react'; import { + Alert, + AlertVariant, Badge, + Bullseye, Flex, FlexItem, + Spinner, Stack, StackItem, Tab, @@ -13,17 +17,52 @@ import { TextContent, TextVariants, } from '@patternfly/react-core'; +import { EdgeModel, NodeModel } from '@patternfly/react-topology'; import useTabs from 'hooks/patternfly/useTabs'; +import useFetchDeployment from 'hooks/useFetchDeployment'; +import { + getListenPorts, + getNumExternalFlows, + getNumInternalFlows, +} from '../utils/networkGraphUtils'; + import DeploymentDetails from './DeploymentDetails'; import DeploymentNetworkPolicies from './DeploymentNetworkPolicies'; import DeploymentFlows from './DeploymentFlows'; -function DeploymentSideBar() { +type DeploymentSideBarProps = { + deploymentId: string; + nodes: NodeModel[]; + edges: EdgeModel[]; +}; + +function DeploymentSideBar({ deploymentId, nodes, edges }: DeploymentSideBarProps) { + // component state + const { deployment, isLoading, error } = useFetchDeployment(deploymentId); const { activeKeyTab, onSelectTab } = useTabs({ defaultTab: 'Details', }); + // derived values + const numExternalFlows = getNumExternalFlows(nodes, edges, deploymentId); + const numInternalFlows = getNumInternalFlows(nodes, edges, deploymentId); + const listenPorts = getListenPorts(nodes, deploymentId); + + if (isLoading) { + return ( + + + + ); + } + + if (error) { + return ( + + ); + } + return ( @@ -34,7 +73,7 @@ function DeploymentSideBar() { - visa-processor + {deployment?.name} @@ -42,7 +81,7 @@ function DeploymentSideBar() { component={TextVariants.h2} className="pf-u-font-size-sm pf-u-color-200" > - in "production / naples" + in "{deployment?.clusterName} / {deployment?.namespace}" @@ -74,7 +113,14 @@ function DeploymentSideBar() {