diff --git a/.changeset/slimy-icons-swim.md b/.changeset/slimy-icons-swim.md new file mode 100644 index 0000000000..52e2769e51 --- /dev/null +++ b/.changeset/slimy-icons-swim.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-org': patch +--- + +Add `relationsType` argument to `MembersListCard`. +This can be used to display an aggregated user list for groups by default. diff --git a/plugins/org/api-report.md b/plugins/org/api-report.md index 922b25b610..1960ce839b 100644 --- a/plugins/org/api-report.md +++ b/plugins/org/api-report.md @@ -23,6 +23,7 @@ export const EntityMembersListCard: (props: { memberDisplayTitle?: string | undefined; pageSize?: number | undefined; showAggregateMembersToggle?: boolean | undefined; + relationsType?: EntityRelationAggregation | undefined; }) => JSX_2.Element; // @public (undocumented) @@ -54,6 +55,7 @@ export const MembersListCard: (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; + relationsType?: EntityRelationAggregation; }) => React_2.JSX.Element; // @public diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index cd5801ac71..06ec3b0ebd 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -311,15 +311,20 @@ describe('MemberTab Test', () => { }, }, ); + + // Should show only direct users on initial load + const displayedMemberNamesBefore = screen.queryAllByTestId('user-link'); + expect(displayedMemberNamesBefore).toHaveLength(2); + // Click the toggle switch await userEvent.click(screen.getByRole('checkbox')); - const displayedMemberNames = screen.queryAllByTestId('user-link'); + const displayedMemberNamesAfter = screen.queryAllByTestId('user-link'); const duplicatedUserText = screen.getByText('Duplicated User'); const groupAUserOneText = screen.getByText('Group A User One'); const groupBUserOneText = screen.getByText('Group B User One'); const groupDUserOneText = screen.getByText('Group D User One'); const groupEUserOneText = screen.getByText('Group E User One'); - expect(displayedMemberNames).toHaveLength(5); + expect(displayedMemberNamesAfter).toHaveLength(5); expect(duplicatedUserText).toBeInTheDocument(); expect(groupAUserOneText).toBeInTheDocument(); expect(groupBUserOneText).toBeInTheDocument(); @@ -339,4 +344,77 @@ describe('MemberTab Test', () => { ); }); }); + + it('Can default to show aggregated members with the aggregate members toggle', async () => { + await renderInTestApp( + + + + + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + // Should show aggregated users on initial load + const displayedMemberNamesBefore = screen.queryAllByTestId('user-link'); + expect(displayedMemberNamesBefore).toHaveLength(5); + + // Click the toggle switch + await userEvent.click(screen.getByRole('checkbox')); + + // Should now show only direct users + const displayedMemberNamesAfter = screen.queryAllByTestId('user-link'); + expect(displayedMemberNamesAfter).toHaveLength(2); + }); + + it('Can show aggregated members without the aggregate members toggle', async () => { + await renderInTestApp( + + + + + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + // aggregated relations checkbox should not be rendered + expect(screen.queryByRole('checkbox')).toBeNull(); + + // Should show all descendant users on load + const displayedMemberNames = screen.queryAllByTestId('user-link'); + expect(displayedMemberNames).toHaveLength(5); + }); }); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 8967e7cdd7..005e426149 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -48,6 +48,7 @@ import { removeDuplicateEntitiesFrom, } from '../../../../helpers/helpers'; import { EntityRefLink } from '@backstage/plugin-catalog-react'; +import { EntityRelationAggregation } from '../../types'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -138,11 +139,13 @@ export const MembersListCard = (props: { memberDisplayTitle?: string; pageSize?: number; showAggregateMembersToggle?: boolean; + relationsType?: EntityRelationAggregation; }) => { const { memberDisplayTitle = 'Members', pageSize = 50, showAggregateMembersToggle, + relationsType = 'direct', } = props; const classes = useListStyles(); @@ -162,11 +165,13 @@ export const MembersListCard = (props: { setPage(pageIndex); }; - const [showAggregateMembers, setShowAggregateMembers] = useState(false); + const [showAggregateMembers, setShowAggregateMembers] = useState( + relationsType === 'aggregated', + ); const { loading: loadingDescendantMembers, value: descendantMembers } = useAsync(async () => { - if (!showAggregateMembersToggle) { + if (!showAggregateMembers) { return [] as UserEntity[]; } @@ -174,7 +179,7 @@ export const MembersListCard = (props: { groupEntity, catalogApi, ); - }, [catalogApi, groupEntity, showAggregateMembersToggle]); + }, [catalogApi, groupEntity, showAggregateMembers]); const { loading, error, @@ -229,7 +234,7 @@ export const MembersListCard = (props: { memberList = ( {members.slice(pageSize * (page - 1), pageSize * page).map(member => ( - + ))} ); diff --git a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx index 1eb2a95ff6..928f242e0d 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx @@ -33,7 +33,7 @@ import React from 'react'; import pluralize from 'pluralize'; import { catalogIndexRouteRef } from '../../../routes'; import { useGetEntities } from './useGetEntities'; -import { EntityRelationAggregation } from './types'; +import { EntityRelationAggregation } from '../types'; const useStyles = makeStyles(theme => createStyles({ diff --git a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx index 278e2f4b70..0747f710ef 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx +++ b/plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx @@ -27,7 +27,7 @@ import { } from '@material-ui/core'; import React, { useEffect, useState } from 'react'; import { ComponentsGrid } from './ComponentsGrid'; -import { EntityRelationAggregation } from './types'; +import { EntityRelationAggregation } from '../types'; const useStyles = makeStyles(theme => ({ card: { diff --git a/plugins/org/src/components/Cards/OwnershipCard/index.ts b/plugins/org/src/components/Cards/OwnershipCard/index.ts index a4798cc4bf..dc0cef0226 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/index.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/index.ts @@ -14,4 +14,3 @@ * limitations under the License. */ export * from './OwnershipCard'; -export * from './types'; diff --git a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts index b6fa9cbfd1..c5bf4a7279 100644 --- a/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts +++ b/plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts @@ -31,7 +31,7 @@ import limiterFactory from 'p-limit'; import { useApi } from '@backstage/core-plugin-api'; import useAsync from 'react-use/lib/useAsync'; import qs from 'qs'; -import { EntityRelationAggregation as EntityRelationsAggregation } from './types'; +import { EntityRelationAggregation } from '../types'; import { uniq } from 'lodash'; const limiter = limiterFactory(10); @@ -125,7 +125,7 @@ const getChildOwnershipEntityRefs = async ( const getOwners = async ( entity: Entity, - relations: EntityRelationsAggregation, + relations: EntityRelationAggregation, catalogApi: CatalogApi, ): Promise => { const isGroup = entity.kind === 'Group'; @@ -166,7 +166,7 @@ const getOwnedEntitiesByOwners = ( export function useGetEntities( entity: Entity, - relations: EntityRelationsAggregation, + relations: EntityRelationAggregation, entityFilterKind?: string[], entityLimit = 6, ): { diff --git a/plugins/org/src/components/Cards/index.ts b/plugins/org/src/components/Cards/index.ts index aec3d8da5e..4c57f5a422 100644 --- a/plugins/org/src/components/Cards/index.ts +++ b/plugins/org/src/components/Cards/index.ts @@ -16,3 +16,4 @@ export * from './Group'; export * from './User'; export * from './OwnershipCard'; +export type { EntityRelationAggregation } from './types'; diff --git a/plugins/org/src/components/Cards/OwnershipCard/types.ts b/plugins/org/src/components/Cards/types.ts similarity index 100% rename from plugins/org/src/components/Cards/OwnershipCard/types.ts rename to plugins/org/src/components/Cards/types.ts