feat: add argument for relationsType to MembersListCard

Signed-off-by: Patrik Ivarsson <patrik.ivarsson@avanza.se>
This commit is contained in:
Patrik Ivarsson
2024-03-07 17:25:01 +01:00
parent fd0ac1543e
commit 2219f8c3d6
9 changed files with 101 additions and 12 deletions
+6
View File
@@ -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.
@@ -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(
<TestApiProvider
apis={[
[catalogApiRef, mockedCatalogApiSupportingGroups],
[starredEntitiesApiRef, mockedStarredEntitiesApi],
[permissionApiRef, {}],
]}
>
<EntityProvider entity={groupA}>
<EntityLayout>
<EntityLayout.Route path="/" title="Title">
<MembersListCard
showAggregateMembersToggle
relationsType="aggregated"
/>
</EntityLayout.Route>
</EntityLayout>
</EntityProvider>
</TestApiProvider>,
{
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(
<TestApiProvider
apis={[
[catalogApiRef, mockedCatalogApiSupportingGroups],
[starredEntitiesApiRef, mockedStarredEntitiesApi],
[permissionApiRef, {}],
]}
>
<EntityProvider entity={groupA}>
<EntityLayout>
<EntityLayout.Route path="/" title="Title">
<MembersListCard relationsType="aggregated" />
</EntityLayout.Route>
</EntityLayout>
</EntityProvider>
</TestApiProvider>,
{
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);
});
});
@@ -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 = (
<Box className={classes.memberList}>
{members.slice(pageSize * (page - 1), pageSize * page).map(member => (
<MemberComponent member={member} key={member.metadata.uid} />
<MemberComponent member={member} key={stringifyEntityRef(member)} />
))}
</Box>
);
@@ -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({
@@ -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: {
@@ -14,4 +14,3 @@
* limitations under the License.
*/
export * from './OwnershipCard';
export * from './types';
@@ -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<string[]> => {
const isGroup = entity.kind === 'Group';
@@ -166,7 +166,7 @@ const getOwnedEntitiesByOwners = (
export function useGetEntities(
entity: Entity,
relations: EntityRelationsAggregation,
relations: EntityRelationAggregation,
entityFilterKind?: string[],
entityLimit = 6,
): {
@@ -16,3 +16,4 @@
export * from './Group';
export * from './User';
export * from './OwnershipCard';
export type { EntityRelationAggregation } from './types';