Skip to content

Commit 2219f8c

Browse files
committed
feat: add argument for relationsType to MembersListCard
Signed-off-by: Patrik Ivarsson <patrik.ivarsson@avanza.se>
1 parent fd0ac15 commit 2219f8c

File tree

9 files changed

+101
-12
lines changed

9 files changed

+101
-12
lines changed

.changeset/slimy-icons-swim.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@backstage/plugin-org': patch
3+
---
4+
5+
Add `relationsType` argument to `MembersListCard`.
6+
This can be used to display an aggregated user list for groups by default.

plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,20 @@ describe('MemberTab Test', () => {
311311
},
312312
},
313313
);
314+
315+
// Should show only direct users on initial load
316+
const displayedMemberNamesBefore = screen.queryAllByTestId('user-link');
317+
expect(displayedMemberNamesBefore).toHaveLength(2);
318+
314319
// Click the toggle switch
315320
await userEvent.click(screen.getByRole('checkbox'));
316-
const displayedMemberNames = screen.queryAllByTestId('user-link');
321+
const displayedMemberNamesAfter = screen.queryAllByTestId('user-link');
317322
const duplicatedUserText = screen.getByText('Duplicated User');
318323
const groupAUserOneText = screen.getByText('Group A User One');
319324
const groupBUserOneText = screen.getByText('Group B User One');
320325
const groupDUserOneText = screen.getByText('Group D User One');
321326
const groupEUserOneText = screen.getByText('Group E User One');
322-
expect(displayedMemberNames).toHaveLength(5);
327+
expect(displayedMemberNamesAfter).toHaveLength(5);
323328
expect(duplicatedUserText).toBeInTheDocument();
324329
expect(groupAUserOneText).toBeInTheDocument();
325330
expect(groupBUserOneText).toBeInTheDocument();
@@ -339,4 +344,77 @@ describe('MemberTab Test', () => {
339344
);
340345
});
341346
});
347+
348+
it('Can default to show aggregated members with the aggregate members toggle', async () => {
349+
await renderInTestApp(
350+
<TestApiProvider
351+
apis={[
352+
[catalogApiRef, mockedCatalogApiSupportingGroups],
353+
[starredEntitiesApiRef, mockedStarredEntitiesApi],
354+
[permissionApiRef, {}],
355+
]}
356+
>
357+
<EntityProvider entity={groupA}>
358+
<EntityLayout>
359+
<EntityLayout.Route path="/" title="Title">
360+
<MembersListCard
361+
showAggregateMembersToggle
362+
relationsType="aggregated"
363+
/>
364+
</EntityLayout.Route>
365+
</EntityLayout>
366+
</EntityProvider>
367+
</TestApiProvider>,
368+
{
369+
mountedRoutes: {
370+
'/catalog/:namespace/:kind/:name': entityRouteRef,
371+
'/catalog': rootRouteRef,
372+
},
373+
},
374+
);
375+
376+
// Should show aggregated users on initial load
377+
const displayedMemberNamesBefore = screen.queryAllByTestId('user-link');
378+
expect(displayedMemberNamesBefore).toHaveLength(5);
379+
380+
// Click the toggle switch
381+
await userEvent.click(screen.getByRole('checkbox'));
382+
383+
// Should now show only direct users
384+
const displayedMemberNamesAfter = screen.queryAllByTestId('user-link');
385+
expect(displayedMemberNamesAfter).toHaveLength(2);
386+
});
387+
388+
it('Can show aggregated members without the aggregate members toggle', async () => {
389+
await renderInTestApp(
390+
<TestApiProvider
391+
apis={[
392+
[catalogApiRef, mockedCatalogApiSupportingGroups],
393+
[starredEntitiesApiRef, mockedStarredEntitiesApi],
394+
[permissionApiRef, {}],
395+
]}
396+
>
397+
<EntityProvider entity={groupA}>
398+
<EntityLayout>
399+
<EntityLayout.Route path="/" title="Title">
400+
<MembersListCard relationsType="aggregated" />
401+
</EntityLayout.Route>
402+
</EntityLayout>
403+
</EntityProvider>
404+
</TestApiProvider>,
405+
{
406+
mountedRoutes: {
407+
'/catalog/:namespace/:kind/:name': entityRouteRef,
408+
'/catalog': rootRouteRef,
409+
},
410+
},
411+
);
412+
413+
// aggregated relations checkbox should not be rendered
414+
expect(screen.queryByRole('checkbox')).toBeNull();
415+
416+
// Should show all descendant users on load
417+
const displayedMemberNames = screen.queryAllByTestId('user-link');
418+
expect(displayedMemberNames).toHaveLength(5);
419+
});
342420
});

plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
removeDuplicateEntitiesFrom,
4949
} from '../../../../helpers/helpers';
5050
import { EntityRefLink } from '@backstage/plugin-catalog-react';
51+
import { EntityRelationAggregation } from '../../types';
5152

5253
const useStyles = makeStyles((theme: Theme) =>
5354
createStyles({
@@ -138,11 +139,13 @@ export const MembersListCard = (props: {
138139
memberDisplayTitle?: string;
139140
pageSize?: number;
140141
showAggregateMembersToggle?: boolean;
142+
relationsType?: EntityRelationAggregation;
141143
}) => {
142144
const {
143145
memberDisplayTitle = 'Members',
144146
pageSize = 50,
145147
showAggregateMembersToggle,
148+
relationsType = 'direct',
146149
} = props;
147150
const classes = useListStyles();
148151

@@ -162,19 +165,21 @@ export const MembersListCard = (props: {
162165
setPage(pageIndex);
163166
};
164167

165-
const [showAggregateMembers, setShowAggregateMembers] = useState(false);
168+
const [showAggregateMembers, setShowAggregateMembers] = useState(
169+
relationsType === 'aggregated',
170+
);
166171

167172
const { loading: loadingDescendantMembers, value: descendantMembers } =
168173
useAsync(async () => {
169-
if (!showAggregateMembersToggle) {
174+
if (!showAggregateMembers) {
170175
return [] as UserEntity[];
171176
}
172177

173178
return await getAllDesendantMembersForGroupEntity(
174179
groupEntity,
175180
catalogApi,
176181
);
177-
}, [catalogApi, groupEntity, showAggregateMembersToggle]);
182+
}, [catalogApi, groupEntity, showAggregateMembers]);
178183
const {
179184
loading,
180185
error,
@@ -229,7 +234,7 @@ export const MembersListCard = (props: {
229234
memberList = (
230235
<Box className={classes.memberList}>
231236
{members.slice(pageSize * (page - 1), pageSize * page).map(member => (
232-
<MemberComponent member={member} key={member.metadata.uid} />
237+
<MemberComponent member={member} key={stringifyEntityRef(member)} />
233238
))}
234239
</Box>
235240
);

plugins/org/src/components/Cards/OwnershipCard/ComponentsGrid.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import React from 'react';
3333
import pluralize from 'pluralize';
3434
import { catalogIndexRouteRef } from '../../../routes';
3535
import { useGetEntities } from './useGetEntities';
36-
import { EntityRelationAggregation } from './types';
36+
import { EntityRelationAggregation } from '../types';
3737

3838
const useStyles = makeStyles(theme =>
3939
createStyles({

plugins/org/src/components/Cards/OwnershipCard/OwnershipCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {
2727
} from '@material-ui/core';
2828
import React, { useEffect, useState } from 'react';
2929
import { ComponentsGrid } from './ComponentsGrid';
30-
import { EntityRelationAggregation } from './types';
30+
import { EntityRelationAggregation } from '../types';
3131

3232
const useStyles = makeStyles(theme => ({
3333
card: {

plugins/org/src/components/Cards/OwnershipCard/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@
1414
* limitations under the License.
1515
*/
1616
export * from './OwnershipCard';
17-
export * from './types';

plugins/org/src/components/Cards/OwnershipCard/useGetEntities.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import limiterFactory from 'p-limit';
3131
import { useApi } from '@backstage/core-plugin-api';
3232
import useAsync from 'react-use/lib/useAsync';
3333
import qs from 'qs';
34-
import { EntityRelationAggregation as EntityRelationsAggregation } from './types';
34+
import { EntityRelationAggregation } from '../types';
3535
import { uniq } from 'lodash';
3636

3737
const limiter = limiterFactory(10);
@@ -125,7 +125,7 @@ const getChildOwnershipEntityRefs = async (
125125

126126
const getOwners = async (
127127
entity: Entity,
128-
relations: EntityRelationsAggregation,
128+
relations: EntityRelationAggregation,
129129
catalogApi: CatalogApi,
130130
): Promise<string[]> => {
131131
const isGroup = entity.kind === 'Group';
@@ -166,7 +166,7 @@ const getOwnedEntitiesByOwners = (
166166

167167
export function useGetEntities(
168168
entity: Entity,
169-
relations: EntityRelationsAggregation,
169+
relations: EntityRelationAggregation,
170170
entityFilterKind?: string[],
171171
entityLimit = 6,
172172
): {

plugins/org/src/components/Cards/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@
1616
export * from './Group';
1717
export * from './User';
1818
export * from './OwnershipCard';
19+
export type { EntityRelationAggregation } from './types';

0 commit comments

Comments
 (0)