diff --git a/.changeset/cool-dolphins-join.md b/.changeset/cool-dolphins-join.md
new file mode 100644
index 0000000000..496cc307e5
--- /dev/null
+++ b/.changeset/cool-dolphins-join.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-org': patch
+---
+
+Link group ownership boxes through filtered catalog page
diff --git a/plugins/org/package.json b/plugins/org/package.json
index 59c86188a8..74bebe7a10 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.9",
diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx
index bfaca73bc0..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,31 +124,24 @@ describe('OwnershipCard', () => {
,
+ {
+ mountedRoutes: {
+ '/create': catalogRouteRef,
+ },
+ },
);
- 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..83768f1513 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 {
@@ -26,28 +27,26 @@ import {
createStyles,
Grid,
makeStyles,
- Tooltip,
Typography,
+ Link,
} 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 } from '@backstage/core-plugin-api';
+import { useApi, useRouteRef } from '@backstage/core-plugin-api';
-type EntitiesKinds = 'Component' | 'API';
-type EntitiesTypes =
- | 'service'
- | 'website'
- | 'library'
- | 'documentation'
- | 'api'
- | 'tool';
+type EntityTypeProps = {
+ kind: string;
+ type: string;
+ count: number;
+};
const createPageTheme = (
theme: BackstageTheme,
@@ -75,69 +74,30 @@ const useStyles = makeStyles((theme: BackstageTheme) =>
bold: {
fontWeight: theme.typography.fontWeightBold,
},
- service: {
- background: createPageTheme(theme, 'home', 'service'),
- },
- website: {
- background: createPageTheme(theme, 'home', 'website'),
- },
- library: {
- background: createPageTheme(theme, 'home', 'library'),
- },
- documentation: {
- background: createPageTheme(theme, 'home', 'documentation'),
- },
- api: {
- background: createPageTheme(theme, 'home', 'home'),
- },
- tool: {
- background: createPageTheme(theme, 'home', 'tool'),
+ entityTypeBox: {
+ background: (props: { type: string }) =>
+ createPageTheme(theme, props.type, props.type),
},
}),
);
-const listEntitiesBy = (
- entities: Array,
- kind: EntitiesKinds,
- type?: EntitiesTypes,
-) =>
- entities.filter(
- e => e.kind === kind && (type ? e?.spec?.type === type : true),
- );
-
-const countEntitiesBy = (
- entities: Array,
- kind: EntitiesKinds,
- type?: EntitiesTypes,
-) => listEntitiesBy(entities, kind, type).length;
-
const EntityCountTile = ({
counter,
- className,
- entities,
+ type,
name,
+ url,
}: {
counter: number;
- className: EntitiesTypes;
- entities: Entity[];
+ type: string;
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(', ')}, ...`;
- }
+ const classes = useStyles({ type });
return (
-
+
-
+
);
};
+const getQueryParams = (
+ owner: Entity,
+ selectedEntity: EntityTypeProps,
+): string => {
+ const ownerName = owner.metadata.name;
+ const { kind, type } = selectedEntity;
+ const queryParams = qs.stringify({
+ filters: {
+ kind,
+ type,
+ owners: ownerName,
+ user: 'all',
+ },
+ });
+
+ return queryParams;
+};
+
export const OwnershipCard = ({
variant,
}: {
@@ -162,6 +140,8 @@ export const OwnershipCard = ({
}) => {
const { entity } = useEntity();
const catalogApi = useApi(catalogApiRef);
+ const catalogLink = useRouteRef(catalogRouteRef);
+
const {
loading,
error,
@@ -185,56 +165,40 @@ export const OwnershipCard = ({
isOwnerOf(entity, component),
);
- return [
- {
- counter: countEntitiesBy(ownedEntitiesList, 'Component', 'service'),
- className: 'service',
- entities: listEntitiesBy(ownedEntitiesList, 'Component', 'service'),
- name: 'Services',
+ const counts = ownedEntitiesList.reduce(
+ (acc: EntityTypeProps[], ownedEntity) => {
+ if (typeof ownedEntity.spec?.type !== 'string') return acc;
+
+ const match = acc.find(
+ x => x.kind === ownedEntity.kind && x.type === ownedEntity.spec?.type,
+ );
+ if (match) {
+ match.count += 1;
+ } else {
+ acc.push({
+ kind: ownedEntity.kind,
+ type: ownedEntity.spec?.type,
+ count: 1,
+ });
+ }
+ return acc;
},
- {
- 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<{
+ [],
+ );
+
+ // 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(topOwnedEntity => ({
+ counter: topOwnedEntity.count,
+ type: topOwnedEntity.type,
+ name: topOwnedEntity.type.toLocaleUpperCase('en-US'),
+ queryParams: getQueryParams(entity, topOwnedEntity),
+ })) as Array<{
counter: number;
- className: EntitiesTypes;
- entities: Entity[];
+ type: string;
name: string;
+ queryParams: string;
}>;
}, [catalogApi, entity]);
@@ -251,9 +215,9 @@ export const OwnershipCard = ({
))}