From e64d1c503ba8d5a4849deae38aa3addb1de9f207 Mon Sep 17 00:00:00 2001 From: Prasetya Aria Wibawa Date: Fri, 13 Aug 2021 21:35:51 +0700 Subject: [PATCH] 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 = ({ ))}