diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx index baa8c667d2..34dfcfef56 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx @@ -62,9 +62,9 @@ describe('', () => { ); expect(queryByText(/System Diagram/)).toBeInTheDocument(); - expect(queryByText(/system:my-namespace2\/my-system2/)).toBeInTheDocument(); + expect(queryByText(/my-namespace2\/my-system2/)).toBeInTheDocument(); expect( - queryByText(/component:my-namespace\/my-entity/), + queryByText(/my-namespace\/my-entity/), ).not.toBeInTheDocument(); }); @@ -118,7 +118,7 @@ describe('', () => { ); expect(getByText('System Diagram')).toBeInTheDocument(); - expect(getByText('system:my-namespace/my-system')).toBeInTheDocument(); - expect(getByText('component:my-namespace/my-entity')).toBeInTheDocument(); + expect(getByText('my-namespace/my-system')).toBeInTheDocument(); + expect(getByText('my-namespace/my-entity')).toBeInTheDocument(); }); }); diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx index e601b443de..c7a9cfdb01 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx @@ -19,11 +19,13 @@ import { RELATION_DEPENDS_ON, RELATION_PROVIDES_API, RELATION_PART_OF, - serializeEntityRef, + stringifyEntityRef, ENTITY_DEFAULT_NAMESPACE, + parseEntityRef, } from '@backstage/catalog-model'; import { catalogApiRef, + entityRoute, getEntityRelations, useEntity, } from '@backstage/plugin-catalog-react'; @@ -34,26 +36,106 @@ import { Progress, useApi, ResponseErrorPanel, + Link, } from '@backstage/core'; -import { Box, Typography } from '@material-ui/core'; +import { Box, makeStyles, Typography } from '@material-ui/core'; import ZoomOutMap from '@material-ui/icons/ZoomOutMap'; import React from 'react'; import { useAsync } from 'react-use'; +import { BackstageTheme } from '@backstage/theme'; +import { generatePath } from 'react-router'; -function simplifiedEntityName( +const useStyles = makeStyles((theme: BackstageTheme) => ({ + domainNode: { + fill: theme.palette.primary.main, + stroke: theme.palette.border, + }, + systemNode: { + fill: 'coral', + stroke: theme.palette.border, + }, + componentNode: { + fill: 'yellowgreen', + stroke: theme.palette.border, + }, + apiNode: { + fill: theme.palette.gold, + stroke: theme.palette.border, + }, + resourceNode: { + fill: 'grey', + stroke: theme.palette.border, + }, +})); + +// Simplifies the diagram output by hiding the default namespace and kind +function readableEntityName( ref: | Entity | { - kind?: string; + kind: string; namespace?: string; name: string; }, ): string { - // Simplify the diagram output by hiding only the default namespace - return serializeEntityRef(ref) - .toString() + return stringifyEntityRef(ref) .toLocaleLowerCase('en-US') - .replace(':default/', ':'); + .replace(`:${ENTITY_DEFAULT_NAMESPACE}/`, ':') + .split(':')[1]; +} + +function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { + const classes = useStyles(); + const kind = props.node.kind || 'Component'; + const ref = parseEntityRef(props.node.id); + let nodeClass = classes.componentNode; + + switch (kind) { + case 'Domain': + nodeClass = classes.domainNode; + break; + case 'System': + nodeClass = classes.systemNode; + break; + case 'Component': + nodeClass = classes.componentNode; + break; + case 'API': + nodeClass = classes.apiNode; + break; + case 'Resource': + nodeClass = classes.resourceNode; + break; + default: + nodeClass = classes.componentNode; + } + + return ( + + + + + {props.node.name} + + + + + {props.node.kind} + + + ); } /** @@ -63,8 +145,8 @@ function simplifiedEntityName( export function SystemDiagramCard() { const { entity } = useEntity(); const currentSystemName = entity.metadata.name; - const currentSystemNode = simplifiedEntityName(entity); - const systemNodes = new Array<{ id: string }>(); + const currentSystemNode = stringifyEntityRef(entity); + const systemNodes = new Array<{ id: string; kind: string; name: string }>(); const systemEdges = new Array<{ from: string; to: string; label: string }>(); const catalogApi = useApi(catalogApiRef); @@ -83,22 +165,26 @@ export function SystemDiagramCard() { // pick out the system itself systemNodes.push({ id: currentSystemNode, + kind: 'System', + name: readableEntityName(entity), }); // check if the system has an assigned domain // even if the domain object doesn't exist in the catalog, display it in the map const catalogItemDomain = getEntityRelations(entity, RELATION_PART_OF, { - kind: 'domain', + kind: 'Domain', }); catalogItemDomain.forEach(foundDomain => systemNodes.push({ - id: simplifiedEntityName(foundDomain), + id: stringifyEntityRef(foundDomain), + kind: foundDomain.kind, + name: readableEntityName(foundDomain), }), ); catalogItemDomain.forEach(foundDomain => systemEdges.push({ from: currentSystemNode, - to: simplifiedEntityName(foundDomain), + to: stringifyEntityRef(foundDomain), label: 'part of', }), ); @@ -106,7 +192,9 @@ export function SystemDiagramCard() { if (catalogResponse && catalogResponse.items) { for (const catalogItem of catalogResponse.items) { systemNodes.push({ - id: simplifiedEntityName(catalogItem), + id: stringifyEntityRef(catalogItem), + kind: catalogItem.kind, + name: readableEntityName(catalogItem), }); // Check relations of the entity assigned to this system to see @@ -119,8 +207,8 @@ export function SystemDiagramCard() { ); catalogItemRelations_partOf.forEach(foundRelation => systemEdges.push({ - from: simplifiedEntityName(catalogItem), - to: simplifiedEntityName(foundRelation), + from: stringifyEntityRef(catalogItem), + to: stringifyEntityRef(foundRelation), label: 'part of', }), ); @@ -131,9 +219,9 @@ export function SystemDiagramCard() { ); catalogItemRelations_providesApi.forEach(foundRelation => systemEdges.push({ - from: simplifiedEntityName(catalogItem), - to: simplifiedEntityName(foundRelation), - label: 'provides API', + from: stringifyEntityRef(catalogItem), + to: stringifyEntityRef(foundRelation), + label: 'provides', }), ); @@ -143,8 +231,8 @@ export function SystemDiagramCard() { ); catalogItemRelations_dependsOn.forEach(foundRelation => systemEdges.push({ - from: simplifiedEntityName(catalogItem), - to: simplifiedEntityName(foundRelation), + from: stringifyEntityRef(catalogItem), + to: stringifyEntityRef(foundRelation), label: 'depends on', }), ); @@ -164,6 +252,7 @@ export function SystemDiagramCard() { edges={systemEdges} nodeMargin={10} direction={DependencyGraphTypes.Direction.BOTTOM_TOP} + renderNode={RenderNode} />