From 7668881972cd6e74775a55a62716d6f6bb9f0204 Mon Sep 17 00:00:00 2001 From: jona Date: Sun, 20 Apr 2025 13:13:03 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=90=9B=20(useEntityListProvider)=20Ad?= =?UTF-8?q?just=20filter=20handling=20for=20user=20and=20group=20types=20t?= =?UTF-8?q?o=20fix=20EntityOwnerPicker=20for=20users/groups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jona Warnecke --- plugins/catalog-react/src/hooks/useEntityListProvider.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 1d3afd8d9b..b0a0a24fb1 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -241,7 +241,13 @@ export const EntityListProvider = ( // based on the requested filters changing. const [{ loading, error }, refresh] = useAsyncFn( async () => { - const compacted = compact(Object.values(requestedFilters)); + const kindValue = + requestedFilters.kind?.value?.toLocaleLowerCase('en-US'); + const effectiveFilters = + kindValue === 'user' || kindValue === 'group' + ? { ...requestedFilters, owners: undefined } + : requestedFilters; + const compacted = compact(Object.values(effectiveFilters)); const queryParams = Object.keys(requestedFilters).reduce( (params, key) => { From 0ca570aa9cf6657cf0a9d21bcc6d88a02e09fb28 Mon Sep 17 00:00:00 2001 From: Jona Warnecke Date: Sun, 20 Apr 2025 17:13:44 +0300 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=90=9B=20(useEntityListProvider)=20Ad?= =?UTF-8?q?just=20filter=20handling=20for=20user=20and=20group=20types=20t?= =?UTF-8?q?o=20fix=20EntityOwnerPicker=20for=20users/groups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jona Warnecke --- plugins/catalog-react/src/hooks/useEntityListProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index b0a0a24fb1..560e2ba987 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -243,11 +243,11 @@ export const EntityListProvider = ( async () => { const kindValue = requestedFilters.kind?.value?.toLocaleLowerCase('en-US'); - const effectiveFilters = + const adjustedFilters = kindValue === 'user' || kindValue === 'group' ? { ...requestedFilters, owners: undefined } : requestedFilters; - const compacted = compact(Object.values(effectiveFilters)); + const compacted = compact(Object.values(adjustedFilters)); const queryParams = Object.keys(requestedFilters).reduce( (params, key) => { From 6d7f0d5475ba8d38ff9668239a95d44ee015e050 Mon Sep 17 00:00:00 2001 From: Jona Warnecke Date: Sun, 20 Apr 2025 17:23:40 +0300 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=90=9B=20(useEntityListProvider)=20Ad?= =?UTF-8?q?just=20filter=20handling=20for=20user=20and=20group=20types=20t?= =?UTF-8?q?o=20fix=20EntityOwnerPicker=20for=20users/groups?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jona Warnecke --- .changeset/pretty-seas-hug.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pretty-seas-hug.md diff --git a/.changeset/pretty-seas-hug.md b/.changeset/pretty-seas-hug.md new file mode 100644 index 0000000000..e512e1e234 --- /dev/null +++ b/.changeset/pretty-seas-hug.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Add filter handling for user and group types to fix EntityOwnerPicker for users/groups From b7f1d15db2cc7e3339e9d8773b097c054679839e Mon Sep 17 00:00:00 2001 From: Jona-Soerensen <144896291+Jona-Soerensen@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:17:48 +0300 Subject: [PATCH 4/5] Update .changeset/pretty-seas-hug.md Co-authored-by: Vincenzo Scamporlino Signed-off-by: Jona-Soerensen <144896291+Jona-Soerensen@users.noreply.github.com> --- .changeset/pretty-seas-hug.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pretty-seas-hug.md b/.changeset/pretty-seas-hug.md index e512e1e234..216f9af18f 100644 --- a/.changeset/pretty-seas-hug.md +++ b/.changeset/pretty-seas-hug.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-react': patch --- -Add filter handling for user and group types to fix EntityOwnerPicker for users/groups +Fixed an issue causing entities of kind user and group to be empty when an owner was selected From aac6d44cc48373f4bed368266956cf14f136b37c Mon Sep 17 00:00:00 2001 From: jona Date: Tue, 22 Apr 2025 15:58:35 +0300 Subject: [PATCH 5/5] :white_check_mark: (useEntityListProvider.test) Add tests to omit owners filter for user and group kinds Signed-off-by: Jona --- .../src/hooks/useEntityListProvider.test.tsx | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 45ed6079cc..de85fa1042 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -32,6 +32,7 @@ import { catalogApiRef } from '../api'; import { MockStarredEntitiesApi, starredEntitiesApiRef } from '../apis'; import { EntityKindFilter, + EntityOwnerFilter, EntityTextFilter, EntityTypeFilter, EntityUserFilter, @@ -298,6 +299,48 @@ describe('', () => { expect(result.current.pageInfo).toBeUndefined(); }); + + it('should omit owners filter when kind is "user"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('user', 'User'), + owners: new EntityOwnerFilter(['user:default/guest']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.getEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.getEntities).toHaveBeenCalledWith({ + filter: { kind: 'user' }, + }); + }); + + it('should omit owners filter when kind is "group"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('group', 'Group'), + owners: new EntityOwnerFilter(['group:default/team-a']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.getEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.getEntities).toHaveBeenCalledWith({ + filter: { kind: 'group' }, + }); + }); }); describe('', () => { @@ -552,6 +595,52 @@ describe('', () => { }); }); }); + + it('should omit owners filter when kind is "user"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('user', 'User'), + owners: new EntityOwnerFilter(['user:default/guest']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ + filter: { kind: 'user' }, + }), + ); + }); + + it('should omit owners filter when kind is "group"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('group', 'Group'), + owners: new EntityOwnerFilter(['group:default/team-a']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ + filter: { kind: 'group' }, + }), + ); + }); }); }); @@ -801,4 +890,50 @@ describe(``, () => { expect(result.current.error).toBeDefined(); }); }); + + it('should omit owners filter when kind is "user"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('user', 'User'), + owners: new EntityOwnerFilter(['user:default/guest']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ + filter: { kind: 'user' }, + }), + ); + }); + + it('should omit owners filter when kind is "group"', async () => { + const { result } = renderHook(() => useEntityList(), { + wrapper: createWrapper({ pagination }), + }); + + act(() => { + result.current.updateFilters({ + kind: new EntityKindFilter('group', 'Group'), + owners: new EntityOwnerFilter(['group:default/team-a']), + }); + }); + + await waitFor(() => { + expect(mockCatalogApi.queryEntities).toHaveBeenCalled(); + }); + + expect(mockCatalogApi.queryEntities).toHaveBeenCalledWith( + expect.objectContaining({ + filter: { kind: 'group' }, + }), + ); + }); });