From 4405be0277f7351c9a9c157d79d4760daa7239de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Sat, 17 Apr 2021 23:33:31 +0200 Subject: [PATCH 1/5] Allow entities to be shown in system diagram to live in different namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Gomez --- .../src/components/SystemDiagramCard/SystemDiagramCard.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx index 78288c46e9..e601b443de 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx @@ -20,6 +20,7 @@ import { RELATION_PROVIDES_API, RELATION_PART_OF, serializeEntityRef, + ENTITY_DEFAULT_NAMESPACE, } from '@backstage/catalog-model'; import { catalogApiRef, @@ -71,7 +72,10 @@ export function SystemDiagramCard() { return catalogApi.getEntities({ filter: { kind: ['Component', 'API', 'Resource', 'System', 'Domain'], - 'spec.system': currentSystemName, + 'spec.system': [ + currentSystemName, + `${ENTITY_DEFAULT_NAMESPACE}/${currentSystemName}`, + ], }, }); }, [catalogApi, currentSystemName]); From e60d55485ce52448e1dc750c652a57010345b11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Sat, 17 Apr 2021 23:41:51 +0200 Subject: [PATCH 2/5] Use different colors for entities kinds in SystemDiagramCard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Gomez --- .../SystemDiagramCard.test.tsx | 8 +- .../SystemDiagramCard/SystemDiagramCard.tsx | 131 +++++++++++++++--- 2 files changed, 114 insertions(+), 25 deletions(-) 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} /> Date: Sun, 18 Apr 2021 00:54:03 +0200 Subject: [PATCH 3/5] Add changeset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Gomez --- .changeset/healthy-stingrays-shout.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/healthy-stingrays-shout.md diff --git a/.changeset/healthy-stingrays-shout.md b/.changeset/healthy-stingrays-shout.md new file mode 100644 index 0000000000..c3ce59ce1f --- /dev/null +++ b/.changeset/healthy-stingrays-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': patch +--- + +SystemDiagramCard UI improvements From cc9af530b3c29d4d55bb8991b00dbe3bf0b339c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Sun, 18 Apr 2021 01:08:08 +0200 Subject: [PATCH 4/5] Fix prettier issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Gomez --- .../components/SystemDiagramCard/SystemDiagramCard.test.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx index 34dfcfef56..738d344941 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx @@ -63,9 +63,7 @@ describe('', () => { expect(queryByText(/System Diagram/)).toBeInTheDocument(); expect(queryByText(/my-namespace2\/my-system2/)).toBeInTheDocument(); - expect( - queryByText(/my-namespace\/my-entity/), - ).not.toBeInTheDocument(); + expect(queryByText(/my-namespace\/my-entity/)).not.toBeInTheDocument(); }); it('shows related systems', async () => { From 693c441923f774c28ef12c99696678147aa7dd73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Sun, 18 Apr 2021 12:44:02 +0200 Subject: [PATCH 5/5] Use entity route ref instead of generate path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Gomez --- .../SystemDiagramCard/SystemDiagramCard.test.tsx | 11 +++++++++++ .../SystemDiagramCard/SystemDiagramCard.tsx | 7 ++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx index 738d344941..337e9d12b6 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.test.tsx @@ -19,6 +19,7 @@ import { catalogApiRef, CatalogApi, EntityProvider, + entityRouteRef, } from '@backstage/plugin-catalog-react'; import { Entity, RELATION_PART_OF } from '@backstage/catalog-model'; import { renderInTestApp } from '@backstage/test-utils'; @@ -59,6 +60,11 @@ describe('', () => { , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, ); expect(queryByText(/System Diagram/)).toBeInTheDocument(); @@ -113,6 +119,11 @@ describe('', () => { , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + }, + }, ); expect(getByText('System Diagram')).toBeInTheDocument(); diff --git a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx index c7a9cfdb01..5fd32a6298 100644 --- a/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx +++ b/plugins/catalog/src/components/SystemDiagramCard/SystemDiagramCard.tsx @@ -25,7 +25,7 @@ import { } from '@backstage/catalog-model'; import { catalogApiRef, - entityRoute, + entityRouteRef, getEntityRelations, useEntity, } from '@backstage/plugin-catalog-react'; @@ -37,13 +37,13 @@ import { useApi, ResponseErrorPanel, Link, + useRouteRef, } from '@backstage/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'; const useStyles = makeStyles((theme: BackstageTheme) => ({ domainNode: { @@ -86,6 +86,7 @@ function readableEntityName( function RenderNode(props: DependencyGraphTypes.RenderNodeProps) { const classes = useStyles(); + const catalogEntityRoute = useRouteRef(entityRouteRef); const kind = props.node.kind || 'Component'; const ref = parseEntityRef(props.node.id); let nodeClass = classes.componentNode; @@ -114,7 +115,7 @@ function RenderNode(props: DependencyGraphTypes.RenderNodeProps) {