From e64d1c503ba8d5a4849deae38aa3addb1de9f207 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 13 Aug 2021 21:35:51 +0700 Subject: [PATCH 01/14] link group ownership boxes through filtered catalog page Signed-off-by: Prasetya Aria Wibawa --- .../OwnershipCard/OwnershipCard.test.tsx | 24 +-- .../Cards/OwnershipCard/OwnershipCard.tsx | 164 +++++++++--------- 2 files changed, 84 insertions(+), 104 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index bfaca73bc0..4bf6d2007a 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -125,29 +125,17 @@ describe('OwnershipCard', () => { , ); - expect(getByText('Services')).toBeInTheDocument(); + expect(getByText('OPENAPI')).toBeInTheDocument(); expect( - queryByText(getByText('Services').parentElement!, '1'), + queryByText(getByText('OPENAPI').parentElement!, '1'), ).toBeInTheDocument(); - expect(getByText('Documentation')).toBeInTheDocument(); + expect(getByText('SERVICE')).toBeInTheDocument(); expect( - queryByText(getByText('Documentation').parentElement!, '0'), + queryByText(getByText('SERVICE').parentElement!, '1'), ).toBeInTheDocument(); - expect(getByText('APIs')).toBeInTheDocument(); + expect(getByText('LIBRARY')).toBeInTheDocument(); expect( - queryByText(getByText('APIs').parentElement!, '1'), - ).toBeInTheDocument(); - expect(getByText('Libraries')).toBeInTheDocument(); - expect( - queryByText(getByText('Libraries').parentElement!, '1'), - ).toBeInTheDocument(); - expect(getByText('Websites')).toBeInTheDocument(); - expect( - queryByText(getByText('Websites').parentElement!, '0'), - ).toBeInTheDocument(); - expect(getByText('Tools')).toBeInTheDocument(); - expect( - queryByText(getByText('Tools').parentElement!, '0'), + queryByText(getByText('LIBRARY').parentElement!, '1'), ).toBeInTheDocument(); }); }); diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 1b82b58389..cd414cbb9a 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -26,8 +26,8 @@ import { createStyles, Grid, makeStyles, - Tooltip, Typography, + Link, } from '@material-ui/core'; import React from 'react'; import { useAsync } from 'react-use'; @@ -38,16 +38,9 @@ import { Progress, ResponseErrorPanel, } from '@backstage/core-components'; -import { useApi } from '@backstage/core-plugin-api'; +import { useApi, configApiRef } from '@backstage/core-plugin-api'; -type EntitiesKinds = 'Component' | 'API'; -type EntitiesTypes = - | 'service' - | 'website' - | 'library' - | 'documentation' - | 'api' - | 'tool'; +type BoxTypes = 'box1' | 'box2' | 'box3' | 'box4' | 'box5' | 'box6'; const createPageTheme = ( theme: BackstageTheme, @@ -75,67 +68,53 @@ const useStyles = makeStyles((theme: BackstageTheme) => bold: { fontWeight: theme.typography.fontWeightBold, }, - service: { + box1: { background: createPageTheme(theme, 'home', 'service'), }, - website: { + box2: { background: createPageTheme(theme, 'home', 'website'), }, - library: { + box3: { background: createPageTheme(theme, 'home', 'library'), }, - documentation: { + box4: { background: createPageTheme(theme, 'home', 'documentation'), }, - api: { + box5: { background: createPageTheme(theme, 'home', 'home'), }, - tool: { + box6: { background: createPageTheme(theme, 'home', 'tool'), }, }), ); -const listEntitiesBy = ( - entities: Array, - kind: EntitiesKinds, - type?: EntitiesTypes, -) => +const listEntitiesBy = (entities: Array, kind: string, type?: string) => entities.filter( e => e.kind === kind && (type ? e?.spec?.type === type : true), ); const countEntitiesBy = ( entities: Array, - kind: EntitiesKinds, - type?: EntitiesTypes, + kind: string, + type?: string, ) => listEntitiesBy(entities, kind, type).length; const EntityCountTile = ({ counter, className, - entities, name, + url, }: { counter: number; - className: EntitiesTypes; - entities: Entity[]; + className: BoxTypes; name: string; + url: string; }) => { - let entityNames; const classes = useStyles(); - if (entities.length < 20) { - entityNames = entities.map(e => e.metadata.name).join(', '); - } else { - entityNames = `${entities - .map(e => e.metadata.name) - .slice(0, 20) - .join(', ')}, ...`; - } - return ( - + - + ); }; +const getFilteredUrl = ( + owner: Entity, + type: string, + entityKind: string, + baseUrl: string, +): string => { + const ownerName = owner.metadata.name; + const filteredUrl = ` + ${baseUrl}/catalog/?filters[kind]=${entityKind}&filters[type][0]=${type}&filters[user]=all&filters[owners][0]=${ownerName} + `; + + return filteredUrl; +}; + export const OwnershipCard = ({ variant, }: { @@ -162,6 +155,8 @@ export const OwnershipCard = ({ }) => { const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); + const baseUrl = useApi(configApiRef).getString('app.baseUrl'); + const { loading, error, @@ -185,56 +180,53 @@ export const OwnershipCard = ({ isOwnerOf(entity, component), ); - return [ - { - counter: countEntitiesBy(ownedEntitiesList, 'Component', 'service'), - className: 'service', - entities: listEntitiesBy(ownedEntitiesList, 'Component', 'service'), - name: 'Services', - }, - { - counter: countEntitiesBy( - ownedEntitiesList, - 'Component', - 'documentation', - ), - className: 'documentation', - entities: listEntitiesBy( - ownedEntitiesList, - 'Component', - 'documentation', - ), - name: 'Documentation', - }, - { - counter: countEntitiesBy(ownedEntitiesList, 'API'), - className: 'api', - entities: listEntitiesBy(ownedEntitiesList, 'API'), - name: 'APIs', - }, - { - counter: countEntitiesBy(ownedEntitiesList, 'Component', 'library'), - className: 'library', - entities: listEntitiesBy(ownedEntitiesList, 'Component', 'library'), - name: 'Libraries', - }, - { - counter: countEntitiesBy(ownedEntitiesList, 'Component', 'website'), - className: 'website', - entities: listEntitiesBy(ownedEntitiesList, 'Component', 'website'), - name: 'Websites', - }, - { - counter: countEntitiesBy(ownedEntitiesList, 'Component', 'tool'), - className: 'tool', - entities: listEntitiesBy(ownedEntitiesList, 'Component', 'tool'), - name: 'Tools', - }, - ] as Array<{ + // Get key-value pair of Entity type and its kind + const entityKindObject = ownedEntitiesList.reduce((acc, ownedEntity) => { + if (typeof ownedEntity.spec?.type !== 'string') return acc; + + const entityType = ownedEntity.spec.type.toLocaleLowerCase('en-US'); + acc[entityType] = ownedEntity.kind; + return acc; + }, {} as Record); + + // Sort by entity count descending, so the most common types appear on top + const countByType = ownedEntitiesList.reduce((acc, ownedEntity) => { + if (typeof ownedEntity.spec?.type !== 'string') return acc; + + const entityType = ownedEntity.spec.type.toLocaleLowerCase('en-US'); + if (!acc[entityType]) { + acc[entityType] = 0; + } + acc[entityType] += 1; + return acc; + }, {} as Record); + + // Get top 6 entity types to be displayed in OwnershipCard + const topSixEntityTypes = Object.entries(countByType) + .sort(([, count1], [, count2]) => count2 - count1) + .map(([type]) => type) + .slice(0, 6); + + return topSixEntityTypes.map((entityType, index) => ({ + counter: countEntitiesBy( + ownedEntitiesList, + entityKindObject[entityType], + entityType, + ), + className: `box${index + 1}`, + name: entityType.toLocaleUpperCase('en-US'), + url: getFilteredUrl( + entity, + entityType, + entityKindObject[entityType], + baseUrl, + ), + })) as Array<{ counter: number; - className: EntitiesTypes; + className: BoxTypes; entities: Entity[]; name: string; + url: string; }>; }, [catalogApi, entity]); @@ -252,8 +244,8 @@ export const OwnershipCard = ({ ))} From a60143c375ed739790eb9a9ef238c5c1f3f7180b Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 13 Aug 2021 21:47:03 +0700 Subject: [PATCH 02/14] commit changeset for link group ownership boxes Signed-off-by: Prasetya Aria Wibawa --- .changeset/cool-dolphins-join.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cool-dolphins-join.md diff --git a/.changeset/cool-dolphins-join.md b/.changeset/cool-dolphins-join.md new file mode 100644 index 0000000000..043e5fba46 --- /dev/null +++ b/.changeset/cool-dolphins-join.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': minor +--- + +Link group ownership boxes through filtered catalog page From 78deecee20a744f36bfcfa293b9aa4881dbb2f88 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Mon, 16 Aug 2021 08:53:30 +0700 Subject: [PATCH 03/14] fix faling test for OwnershipCard.test.tsx Signed-off-by: Prasetya Aria Wibawa --- .../OwnershipCard/OwnershipCard.test.tsx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 4bf6d2007a..e16d4eab69 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -24,7 +24,12 @@ import { renderInTestApp } from '@backstage/test-utils'; import { queryByText } from '@testing-library/react'; import React from 'react'; import { OwnershipCard } from './OwnershipCard'; -import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; +import { + ApiProvider, + ApiRegistry, + ConfigReader, +} from '@backstage/core-app-api'; +import { ConfigApi, configApiRef } from '@backstage/core-plugin-api'; describe('OwnershipCard', () => { const userEntity: GroupEntity = { @@ -117,8 +122,19 @@ describe('OwnershipCard', () => { ] as any, }); + const configApi: ConfigApi = new ConfigReader({ + app: { + baseUrl: 'http://localhost:3000', + }, + }); + const { getByText } = await renderInTestApp( - + From 08707c81a04432adb5237160119ab81f41f28f28 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Mon, 16 Aug 2021 16:57:17 +0700 Subject: [PATCH 04/14] remove entities from attribute of topSixEntityTypes arrray Signed-off-by: Prasetya Aria Wibawa --- plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index cd414cbb9a..b9989d742b 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -224,7 +224,6 @@ export const OwnershipCard = ({ })) as Array<{ counter: number; className: BoxTypes; - entities: Entity[]; name: string; url: string; }>; From 8ab8c325cd8597e7476797bfa378255ad5894208 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Thu, 19 Aug 2021 16:43:00 +0700 Subject: [PATCH 05/14] add qs for queryParams in OwnershipCard component Signed-off-by: Prasetya Aria Wibawa --- plugins/org/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/org/package.json b/plugins/org/package.json index c6be40fc51..8b0b3e3974 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -32,7 +32,8 @@ "react-dom": "^16.13.1", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", - "react-use": "^17.2.4" + "react-use": "^17.2.4", + "qs": "^6.10.1" }, "devDependencies": { "@backstage/cli": "^0.7.8", From 50be33b3cc0875837c9d54de0e994eb2aeb8260a Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Thu, 19 Aug 2021 16:44:38 +0700 Subject: [PATCH 06/14] pass through the owned list once and compute the counts at that time. Signed-off-by: Prasetya Aria Wibawa --- .../Cards/OwnershipCard/OwnershipCard.tsx | 106 ++++++++---------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index b9989d742b..51c39bfbe4 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -31,17 +31,25 @@ import { } from '@material-ui/core'; import React from 'react'; import { useAsync } from 'react-use'; - +import { generatePath } from 'react-router'; +import qs from 'qs'; import { InfoCard, InfoCardVariants, Progress, ResponseErrorPanel, } from '@backstage/core-components'; -import { useApi, configApiRef } from '@backstage/core-plugin-api'; +import { useApi } from '@backstage/core-plugin-api'; type BoxTypes = 'box1' | 'box2' | 'box3' | 'box4' | 'box5' | 'box6'; +type EntityTypeProps = { + name: string; + kind: string; + type: string; + count: number; +}; + const createPageTheme = ( theme: BackstageTheme, shapeKey: string, @@ -89,17 +97,6 @@ const useStyles = makeStyles((theme: BackstageTheme) => }), ); -const listEntitiesBy = (entities: Array, kind: string, type?: string) => - entities.filter( - e => e.kind === kind && (type ? e?.spec?.type === type : true), - ); - -const countEntitiesBy = ( - entities: Array, - kind: string, - type?: string, -) => listEntitiesBy(entities, kind, type).length; - const EntityCountTile = ({ counter, className, @@ -134,14 +131,20 @@ const EntityCountTile = ({ const getFilteredUrl = ( owner: Entity, - type: string, - entityKind: string, - baseUrl: string, + selectedEntity: EntityTypeProps, ): string => { const ownerName = owner.metadata.name; - const filteredUrl = ` - ${baseUrl}/catalog/?filters[kind]=${entityKind}&filters[type][0]=${type}&filters[user]=all&filters[owners][0]=${ownerName} - `; + const kind = selectedEntity.kind; + const type = selectedEntity.type; + const queryParams = qs.stringify({ + filters: { + kind, + type, + owners: ownerName, + user: 'all', + }, + }); + const filteredUrl = generatePath(`/catalog/?${queryParams}`); return filteredUrl; }; @@ -155,7 +158,6 @@ export const OwnershipCard = ({ }) => { const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); - const baseUrl = useApi(configApiRef).getString('app.baseUrl'); const { loading, @@ -180,47 +182,37 @@ export const OwnershipCard = ({ isOwnerOf(entity, component), ); - // Get key-value pair of Entity type and its kind - const entityKindObject = ownedEntitiesList.reduce((acc, ownedEntity) => { - if (typeof ownedEntity.spec?.type !== 'string') return acc; + const counts = ownedEntitiesList.reduce( + (acc: EntityTypeProps[], ownedEntity) => { + if (typeof ownedEntity.spec?.type !== 'string') return acc; - const entityType = ownedEntity.spec.type.toLocaleLowerCase('en-US'); - acc[entityType] = ownedEntity.kind; - return acc; - }, {} as Record); + const match = acc.find( + x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, + ); + const name = ownedEntity.metadata.name; + if (match) { + match.count += 1; + } else { + acc.push({ + name, + kind: ownedEntity.kind, + type: ownedEntity.spec?.type?.toString(), + count: 1, + }); + } + return acc; + }, + [], + ); - // Sort by entity count descending, so the most common types appear on top - const countByType = ownedEntitiesList.reduce((acc, ownedEntity) => { - if (typeof ownedEntity.spec?.type !== 'string') return acc; + // Return top N (six) entities to be displayed in ownership boxes + const topN = counts.sort((a, b) => b.count - a.count).slice(0, 6); - const entityType = ownedEntity.spec.type.toLocaleLowerCase('en-US'); - if (!acc[entityType]) { - acc[entityType] = 0; - } - acc[entityType] += 1; - return acc; - }, {} as Record); - - // Get top 6 entity types to be displayed in OwnershipCard - const topSixEntityTypes = Object.entries(countByType) - .sort(([, count1], [, count2]) => count2 - count1) - .map(([type]) => type) - .slice(0, 6); - - return topSixEntityTypes.map((entityType, index) => ({ - counter: countEntitiesBy( - ownedEntitiesList, - entityKindObject[entityType], - entityType, - ), + return topN.map((topEntity, index) => ({ + counter: topEntity.count, className: `box${index + 1}`, - name: entityType.toLocaleUpperCase('en-US'), - url: getFilteredUrl( - entity, - entityType, - entityKindObject[entityType], - baseUrl, - ), + name: topEntity.type.toLocaleUpperCase('en-US'), + url: getFilteredUrl(entity, topEntity), })) as Array<{ counter: number; className: BoxTypes; From 3d81fa911188e72152eb7765f3956befe93bbd56 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Thu, 19 Aug 2021 16:45:53 +0700 Subject: [PATCH 07/14] change test to not use configApiRef Signed-off-by: Prasetya Aria Wibawa --- .../OwnershipCard/OwnershipCard.test.tsx | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index e16d4eab69..4bf6d2007a 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -24,12 +24,7 @@ import { renderInTestApp } from '@backstage/test-utils'; import { queryByText } from '@testing-library/react'; import React from 'react'; import { OwnershipCard } from './OwnershipCard'; -import { - ApiProvider, - ApiRegistry, - ConfigReader, -} from '@backstage/core-app-api'; -import { ConfigApi, configApiRef } from '@backstage/core-plugin-api'; +import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; describe('OwnershipCard', () => { const userEntity: GroupEntity = { @@ -122,19 +117,8 @@ describe('OwnershipCard', () => { ] as any, }); - const configApi: ConfigApi = new ConfigReader({ - app: { - baseUrl: 'http://localhost:3000', - }, - }); - const { getByText } = await renderInTestApp( - + From 951b666cea0a096d267f7d56775144f9181d8fcc Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Thu, 19 Aug 2021 18:55:34 +0700 Subject: [PATCH 08/14] changeset change to use patch Signed-off-by: Prasetya Aria Wibawa --- .changeset/cool-dolphins-join.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/cool-dolphins-join.md b/.changeset/cool-dolphins-join.md index 043e5fba46..496cc307e5 100644 --- a/.changeset/cool-dolphins-join.md +++ b/.changeset/cool-dolphins-join.md @@ -1,5 +1,5 @@ --- -'@backstage/plugin-org': minor +'@backstage/plugin-org': patch --- Link group ownership boxes through filtered catalog page From 5c6ce92388d043c27e9547385fae195e0adcc4dc Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 20 Aug 2021 09:18:10 +0700 Subject: [PATCH 09/14] use type as props to dynamically set background theme for ownership boxes Signed-off-by: Prasetya Aria Wibawa --- .../Cards/OwnershipCard/OwnershipCard.tsx | 62 ++++++++----------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 51c39bfbe4..2c7e1db2eb 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -41,8 +41,6 @@ import { } from '@backstage/core-components'; import { useApi } from '@backstage/core-plugin-api'; -type BoxTypes = 'box1' | 'box2' | 'box3' | 'box4' | 'box5' | 'box6'; - type EntityTypeProps = { name: string; kind: string; @@ -76,44 +74,35 @@ const useStyles = makeStyles((theme: BackstageTheme) => bold: { fontWeight: theme.typography.fontWeightBold, }, - box1: { - background: createPageTheme(theme, 'home', 'service'), - }, - box2: { - background: createPageTheme(theme, 'home', 'website'), - }, - box3: { - background: createPageTheme(theme, 'home', 'library'), - }, - box4: { - background: createPageTheme(theme, 'home', 'documentation'), - }, - box5: { - background: createPageTheme(theme, 'home', 'home'), - }, - box6: { - background: createPageTheme(theme, 'home', 'tool'), + entityTypeBox: { + background: (props: { type: string }) => + createPageTheme(theme, props.type, props.type), }, }), ); const EntityCountTile = ({ counter, - className, + type, name, - url, + queryParams, }: { counter: number; - className: BoxTypes; + type: string; name: string; - url: string; + queryParams: string; }) => { - const classes = useStyles(); + const classes = useStyles({ type }); return ( - + { @@ -144,9 +133,8 @@ const getFilteredUrl = ( user: 'all', }, }); - const filteredUrl = generatePath(`/catalog/?${queryParams}`); - return filteredUrl; + return queryParams; }; export const OwnershipCard = ({ @@ -196,7 +184,7 @@ export const OwnershipCard = ({ acc.push({ name, kind: ownedEntity.kind, - type: ownedEntity.spec?.type?.toString(), + type: ownedEntity.spec?.type, count: 1, }); } @@ -208,16 +196,16 @@ export const OwnershipCard = ({ // Return top N (six) entities to be displayed in ownership boxes const topN = counts.sort((a, b) => b.count - a.count).slice(0, 6); - return topN.map((topEntity, index) => ({ + return topN.map(topEntity => ({ counter: topEntity.count, - className: `box${index + 1}`, + type: topEntity.type, name: topEntity.type.toLocaleUpperCase('en-US'), - url: getFilteredUrl(entity, topEntity), + queryParams: getQueryParams(entity, topEntity), })) as Array<{ counter: number; - className: BoxTypes; + type: string; name: string; - url: string; + queryParams: string; }>; }, [catalogApi, entity]); @@ -234,9 +222,9 @@ export const OwnershipCard = ({ ))} From ecd571237f04b676f2877b55c9f67d8fe81f362d Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 20 Aug 2021 09:53:04 +0700 Subject: [PATCH 10/14] use catalogRouteRef to generate url path Signed-off-by: Prasetya Aria Wibawa --- .../components/Cards/OwnershipCard/OwnershipCard.test.tsx | 6 ++++++ .../src/components/Cards/OwnershipCard/OwnershipCard.tsx | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index 4bf6d2007a..eab3606f77 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -19,6 +19,7 @@ import { CatalogApi, catalogApiRef, EntityProvider, + catalogRouteRef, } from '@backstage/plugin-catalog-react'; import { renderInTestApp } from '@backstage/test-utils'; import { queryByText } from '@testing-library/react'; @@ -123,6 +124,11 @@ describe('OwnershipCard', () => { , + { + mountedRoutes: { + '/create': catalogRouteRef, + }, + }, ); expect(getByText('OPENAPI')).toBeInTheDocument(); diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 2c7e1db2eb..00e20bb709 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -19,6 +19,7 @@ import { catalogApiRef, isOwnerOf, useEntity, + catalogRouteRef, } from '@backstage/plugin-catalog-react'; import { BackstageTheme, genPageTheme } from '@backstage/theme'; import { @@ -39,7 +40,7 @@ import { Progress, ResponseErrorPanel, } from '@backstage/core-components'; -import { useApi } from '@backstage/core-plugin-api'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; type EntityTypeProps = { name: string; @@ -93,10 +94,11 @@ const EntityCountTile = ({ queryParams: string; }) => { const classes = useStyles({ type }); + const catalogLink = useRouteRef(catalogRouteRef); return ( Date: Fri, 20 Aug 2021 10:50:30 +0700 Subject: [PATCH 11/14] use destructuring for selectedEntityType object Signed-off-by: Prasetya Aria Wibawa --- .../org/src/components/Cards/OwnershipCard/OwnershipCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 00e20bb709..7f14378632 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -125,8 +125,7 @@ const getQueryParams = ( selectedEntity: EntityTypeProps, ): string => { const ownerName = owner.metadata.name; - const kind = selectedEntity.kind; - const type = selectedEntity.type; + const { kind, type } = selectedEntity; const queryParams = qs.stringify({ filters: { kind, From c252c9fee88a0d768a7ba5e359072235a5a522c7 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 20 Aug 2021 11:50:54 +0700 Subject: [PATCH 12/14] move url generation to the main OwnershipCard component Signed-off-by: Prasetya Aria Wibawa --- .../Cards/OwnershipCard/OwnershipCard.tsx | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 7f14378632..57b4c58784 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -86,23 +86,17 @@ const EntityCountTile = ({ counter, type, name, - queryParams, + url, }: { counter: number; type: string; name: string; - queryParams: string; + url: string; }) => { const classes = useStyles({ type }); - const catalogLink = useRouteRef(catalogRouteRef); return ( - + { const { entity } = useEntity(); const catalogApi = useApi(catalogApiRef); + const catalogLink = useRouteRef(catalogRouteRef); const { loading, @@ -225,7 +220,7 @@ export const OwnershipCard = ({ counter={c.counter} type={c.type} name={c.name} - queryParams={c.queryParams} + url={generatePath(`${catalogLink()}/?${c.queryParams}`)} /> ))} From 1dab504713ee0e76ce6a41ec0a5fc0439444672b Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 20 Aug 2021 12:00:05 +0700 Subject: [PATCH 13/14] rename topEntity to be topOwnedEntity Signed-off-by: Prasetya Aria Wibawa --- .../components/Cards/OwnershipCard/OwnershipCard.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 57b4c58784..3cc86200ee 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -192,11 +192,11 @@ export const OwnershipCard = ({ // Return top N (six) entities to be displayed in ownership boxes const topN = counts.sort((a, b) => b.count - a.count).slice(0, 6); - return topN.map(topEntity => ({ - counter: topEntity.count, - type: topEntity.type, - name: topEntity.type.toLocaleUpperCase('en-US'), - queryParams: getQueryParams(entity, topEntity), + return topN.map(topOwnedEntity => ({ + counter: topOwnedEntity.count, + type: topOwnedEntity.type, + name: topOwnedEntity.type.toLocaleUpperCase('en-US'), + queryParams: getQueryParams(entity, topOwnedEntity), })) as Array<{ counter: number; type: string; From c64c03928949547df6057c3f17663dcfd4bdd108 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 20 Aug 2021 12:10:22 +0700 Subject: [PATCH 14/14] remove name from EntityTypeProps attribute Signed-off-by: Prasetya Aria Wibawa --- .../org/src/components/Cards/OwnershipCard/OwnershipCard.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 3cc86200ee..83768f1513 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -43,7 +43,6 @@ import { import { useApi, useRouteRef } from '@backstage/core-plugin-api'; type EntityTypeProps = { - name: string; kind: string; type: string; count: number; @@ -173,12 +172,10 @@ export const OwnershipCard = ({ const match = acc.find( x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type, ); - const name = ownedEntity.metadata.name; if (match) { match.count += 1; } else { acc.push({ - name, kind: ownedEntity.kind, type: ownedEntity.spec?.type, count: 1,