diff --git a/.changeset/eight-elephants-agree.md b/.changeset/eight-elephants-agree.md new file mode 100644 index 0000000000..abe8250fa5 --- /dev/null +++ b/.changeset/eight-elephants-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Change the OwnershipCard link on an user profile, including the user's groups on the filters. diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx index eab3606f77..b5ffd37083 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.test.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { GroupEntity } from '@backstage/catalog-model'; +import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { CatalogApi, catalogApiRef, @@ -28,7 +28,7 @@ import { OwnershipCard } from './OwnershipCard'; import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; describe('OwnershipCard', () => { - const userEntity: GroupEntity = { + const groupEntity: GroupEntity = { apiVersion: 'backstage.io/v1alpha1', kind: 'Group', metadata: { @@ -50,77 +50,79 @@ describe('OwnershipCard', () => { ], }; + const items = [ + { + kind: 'API', + metadata: { + name: 'my-api', + }, + spec: { + type: 'openapi', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-service', + }, + spec: { + type: 'service', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + { + kind: 'Component', + metadata: { + name: 'my-library', + namespace: 'other-namespace', + }, + spec: { + type: 'library', + }, + relations: [ + { + type: 'ownedBy', + target: { + name: 'my-team', + namespace: 'default', + kind: 'Group', + }, + }, + ], + }, + ] as any; + it('displays entity counts', async () => { const catalogApi: jest.Mocked = { getEntities: jest.fn(), } as any; catalogApi.getEntities.mockResolvedValue({ - items: [ - { - kind: 'API', - metadata: { - name: 'my-api', - }, - spec: { - type: 'openapi', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-service', - }, - spec: { - type: 'service', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - { - kind: 'Component', - metadata: { - name: 'my-library', - namespace: 'other-namespace', - }, - spec: { - type: 'library', - }, - relations: [ - { - type: 'ownedBy', - target: { - name: 'my-team', - namespace: 'default', - kind: 'Group', - }, - }, - ], - }, - ] as any, + items, }); const { getByText } = await renderInTestApp( - + , @@ -144,4 +146,80 @@ describe('OwnershipCard', () => { queryByText(getByText('LIBRARY').parentElement!, '1'), ).toBeInTheDocument(); }); + + it('links to the catalog with the group filter', async () => { + const catalogApi: jest.Mocked = { + getEntities: jest.fn(), + } as any; + + catalogApi.getEntities.mockResolvedValue({ + items, + }); + + const { getByText } = await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/create': catalogRouteRef, + }, + }, + ); + + expect(getByText('OPENAPI').closest('a')).toHaveAttribute( + 'href', + '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D%5B0%5D=my-team&filters%5Buser%5D=all', + ); + }); + + it('links to the catalog with the user and groups filters from an user profile', async () => { + const userEntity: UserEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'User', + metadata: { + name: 'the-user', + }, + spec: { + memberOf: ['my-team'], + }, + relations: [ + { + type: 'memberOf', + target: { + kind: 'Group', + name: 'my-team', + namespace: 'default', + }, + }, + ], + }; + const catalogApi: jest.Mocked = { + getEntities: jest.fn(), + } as any; + + catalogApi.getEntities.mockResolvedValue({ + items, + }); + + const { getByText } = await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/create': catalogRouteRef, + }, + }, + ); + + expect(getByText('OPENAPI').closest('a')).toHaveAttribute( + 'href', + '/create/?filters%5Bkind%5D=API&filters%5Btype%5D=openapi&filters%5Bowners%5D%5B0%5D=user%3Athe-user&filters%5Bowners%5D%5B1%5D=my-team&filters%5Buser%5D=all', + ); + }); }); diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 96e7d08c31..fe23191779 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import { Entity, UserEntity } from '@backstage/catalog-model'; import { InfoCard, InfoCardVariants, @@ -109,13 +109,18 @@ const getQueryParams = ( ): string => { const ownerName = formatEntityRefTitle(owner, { defaultKind: 'group' }); const { kind, type } = selectedEntity; + const filters = { + kind, + type, + owners: [ownerName], + user: 'all', + }; + if (owner.kind === 'User') { + const user = owner as UserEntity; + filters.owners = [...filters.owners, ...user.spec.memberOf]; + } const queryParams = qs.stringify({ - filters: { - kind, - type, - owners: ownerName, - user: 'all', - }, + filters, }); return queryParams;