From 72b88270e0f1322319507dec452b7c6c6da600c0 Mon Sep 17 00:00:00 2001 From: Aramis Date: Thu, 25 Jan 2024 19:07:39 -0500 Subject: [PATCH 1/5] feat(catalog): Add a title to the PaginatedCatalogTable. Signed-off-by: Aramis Signed-off-by: aramissennyeydd --- .changeset/perfect-chefs-act.md | 5 +++++ .changeset/rare-worms-sort.md | 5 +++++ .../src/hooks/useEntityListProvider.test.tsx | 6 ++++++ .../src/hooks/useEntityListProvider.tsx | 14 ++++++++++++-- .../src/components/CatalogTable/CatalogTable.tsx | 7 ++++--- .../CatalogTable/PaginatedCatalogTable.tsx | 3 ++- 6 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 .changeset/perfect-chefs-act.md create mode 100644 .changeset/rare-worms-sort.md diff --git a/.changeset/perfect-chefs-act.md b/.changeset/perfect-chefs-act.md new file mode 100644 index 0000000000..99abbae19d --- /dev/null +++ b/.changeset/perfect-chefs-act.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': minor +--- + +Number of results is now directly added as the field `count` on `useEntityList`. diff --git a/.changeset/rare-worms-sort.md b/.changeset/rare-worms-sort.md new file mode 100644 index 0000000000..6b2175d6d9 --- /dev/null +++ b/.changeset/rare-worms-sort.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Adds a title to the `PaginatedCatalogTable` for better visibility on what you're viewing. diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index c2328a1aef..5f8bf361f1 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -235,6 +235,7 @@ describe('', () => { await waitFor(() => { expect(result.current.entities.length).toBe(1); }); + expect(result.current.count).toBe(1); await expect(() => waitFor(() => { @@ -251,6 +252,7 @@ describe('', () => { await waitFor(() => { expect(result.current.backendEntities.length).toBeGreaterThan(0); }); + expect(result.current.count).toBe(2); expect(result.current.backendEntities.length).toBe(2); expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); @@ -276,6 +278,8 @@ describe('', () => { }); expect(result.current.backendEntities.length).toBe(2); + expect(result.current.count).toBe(2); + mockCatalogApi.getEntities!.mockRejectedValueOnce('error'); act(() => { result.current.updateFilters({ kind: new EntityKindFilter('api') }); @@ -455,6 +459,8 @@ describe('', () => { orderFields, }); }); + + expect(result.current.count).toBe(10); }); it('returns an error on catalogApi failure', async () => { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index abb366a568..1f2300c1c5 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -108,6 +108,8 @@ export type EntityListContextProps< next?: () => void; prev?: () => void; }; + + count?: number; }; /** @@ -124,6 +126,7 @@ type OutputState = { entities: Entity[]; backendEntities: Entity[]; pageInfo?: QueryEntitiesResponse['pageInfo']; + count?: number; }; /** @@ -223,6 +226,7 @@ export const EntityListProvider = ( backendEntities: response.items, entities: response.items.filter(entityFilter), pageInfo: response.pageInfo, + count: response.totalItems, }); } } else { @@ -243,6 +247,7 @@ export const EntityListProvider = ( backendEntities: response.items, entities: response.items.filter(entityFilter), pageInfo: response.pageInfo, + count: response.totalItems, }); } } @@ -262,16 +267,20 @@ export const EntityListProvider = ( const response = await catalogApi.getEntities({ filter: backendFilter, }); + const entities = response.items.filter(entityFilter); setOutputState({ appliedFilters: requestedFilters, backendEntities: response.items, - entities: response.items.filter(entityFilter), + entities, + count: entities.length, }); } else { + const entities = outputState.backendEntities.filter(entityFilter); setOutputState({ appliedFilters: requestedFilters, backendEntities: outputState.backendEntities, - entities: outputState.backendEntities.filter(entityFilter), + entities, + count: entities.length, }); } } @@ -352,6 +361,7 @@ export const EntityListProvider = ( loading, error, pageInfo, + count: outputState.count, }), [outputState, updateFilters, queryParameters, loading, error, pageInfo], ); diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index 7da12d7138..a233499fde 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -88,7 +88,8 @@ export const CatalogTable = (props: CatalogTableProps) => { } = props; const { isStarredEntity, toggleStarredEntity } = useStarredEntities(); const entityListContext = useEntityList(); - const { loading, error, entities, filters, pageInfo } = entityListContext; + const { loading, error, entities, filters, pageInfo, count } = + entityListContext; const enablePagination = !!pageInfo; const tableColumns = useMemo( @@ -175,7 +176,7 @@ export const CatalogTable = (props: CatalogTableProps) => { .filter(s => s) .join(' '); - const title = `${titleDisplay} (${entities.length})`; + const title = `${titleDisplay} (${count})`; const actions = props.actions || defaultActions; const options = { actionsColumnIndex: -1, @@ -216,7 +217,7 @@ export const CatalogTable = (props: CatalogTableProps) => { pageSizeOptions: [20, 50, 100], ...options, }} - title={`${titleDisplay} (${entities.length})`} + title={title} data={rows} actions={actions} subtitle={subtitle} diff --git a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx index 0311cd22ca..fa40756a44 100644 --- a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.tsx @@ -32,11 +32,12 @@ type PaginatedCatalogTableProps = { * @internal */ export function PaginatedCatalogTable(props: PaginatedCatalogTableProps) { - const { columns, data, next, prev } = props; + const { columns, data, next, prev, title, isLoading } = props; const { updateFilters } = useEntityList(); return ( Date: Thu, 25 Jan 2024 19:36:33 -0500 Subject: [PATCH 2/5] add test for count Signed-off-by: Aramis Signed-off-by: aramissennyeydd --- .../catalog-react/src/testUtils/providers.tsx | 1 + .../PaginatedCatalogTable.test.tsx | 34 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/plugins/catalog-react/src/testUtils/providers.tsx b/plugins/catalog-react/src/testUtils/providers.tsx index 8ab6d118a9..ae99352f2c 100644 --- a/plugins/catalog-react/src/testUtils/providers.tsx +++ b/plugins/catalog-react/src/testUtils/providers.tsx @@ -71,6 +71,7 @@ export function MockEntityListContextProvider< loading: value?.loading ?? false, queryParameters: value?.queryParameters ?? defaultValues.queryParameters, error: value?.error, + count: (value?.entities ?? defaultValues.entities).length, }), [value, defaultValues, filters, updateFilters], ); diff --git a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx index eb1acc0cee..84f9beea7c 100644 --- a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx @@ -14,14 +14,16 @@ * limitations under the License. */ import React, { ReactNode } from 'react'; -import { fireEvent, render } from '@testing-library/react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; import { PaginatedCatalogTable } from './PaginatedCatalogTable'; import { screen } from '@testing-library/react'; import { CatalogTableRow } from './types'; +import { renderInTestApp } from '@backstage/test-utils'; import { + EntityKindFilter, + MockEntityListContextProvider, DefaultEntityFilters, EntityListContextProps, - MockEntityListContextProvider, } from '@backstage/plugin-catalog-react'; describe('PaginatedCatalogTable', () => { @@ -134,4 +136,32 @@ describe('PaginatedCatalogTable', () => { fireEvent.click(prevButton); expect(fn).toHaveBeenCalled(); }); + + it('should display entity names when loading has finished and no error occurred', async () => { + await renderInTestApp( + e.entity), + count: data.length, + filters: { + kind: new EntityKindFilter('component'), + }, + }} + > + + , + ); + + expect(screen.getByText(/component-0/)).toBeInTheDocument(); + expect(screen.getByText(/component-50/)).toBeInTheDocument(); + expect(screen.getByText(/component-99/)).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/My title/)).toBeInTheDocument(); + }); + }); }); From 59bf5009a856257cfc1464fb60441b71bcc3bdd0 Mon Sep 17 00:00:00 2001 From: Aramis Date: Thu, 25 Jan 2024 20:30:28 -0500 Subject: [PATCH 3/5] fix api report Signed-off-by: Aramis Signed-off-by: aramissennyeydd --- plugins/catalog-react/api-report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index dfb5780a2c..7f9d0908a3 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -306,6 +306,7 @@ export type EntityListContextProps< next?: () => void; prev?: () => void; }; + count?: number; }; // @public From 9291354f9954d3fc4ea8dec0fb77bede91844a8a Mon Sep 17 00:00:00 2001 From: Aramis Date: Fri, 26 Jan 2024 11:53:36 -0500 Subject: [PATCH 4/5] rename `count` to `totalItems` Signed-off-by: Aramis Signed-off-by: aramissennyeydd --- plugins/catalog-react/api-report.md | 2 +- .../src/hooks/useEntityListProvider.test.tsx | 8 ++++---- .../src/hooks/useEntityListProvider.tsx | 14 +++++++------- plugins/catalog-react/src/testUtils/providers.tsx | 3 ++- .../src/components/CatalogTable/CatalogTable.tsx | 4 ++-- .../CatalogTable/PaginatedCatalogTable.test.tsx | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index 7f9d0908a3..ce2502691f 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -306,7 +306,7 @@ export type EntityListContextProps< next?: () => void; prev?: () => void; }; - count?: number; + totalItems?: number; }; // @public diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx index 5f8bf361f1..bc8e6b6038 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.test.tsx @@ -235,7 +235,7 @@ describe('', () => { await waitFor(() => { expect(result.current.entities.length).toBe(1); }); - expect(result.current.count).toBe(1); + expect(result.current.totalItems).toBe(1); await expect(() => waitFor(() => { @@ -252,7 +252,7 @@ describe('', () => { await waitFor(() => { expect(result.current.backendEntities.length).toBeGreaterThan(0); }); - expect(result.current.count).toBe(2); + expect(result.current.totalItems).toBe(2); expect(result.current.backendEntities.length).toBe(2); expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1); @@ -278,7 +278,7 @@ describe('', () => { }); expect(result.current.backendEntities.length).toBe(2); - expect(result.current.count).toBe(2); + expect(result.current.totalItems).toBe(2); mockCatalogApi.getEntities!.mockRejectedValueOnce('error'); act(() => { @@ -460,7 +460,7 @@ describe('', () => { }); }); - expect(result.current.count).toBe(10); + expect(result.current.totalItems).toBe(10); }); it('returns an error on catalogApi failure', async () => { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 1f2300c1c5..c81a399040 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -109,7 +109,7 @@ export type EntityListContextProps< prev?: () => void; }; - count?: number; + totalItems?: number; }; /** @@ -126,7 +126,7 @@ type OutputState = { entities: Entity[]; backendEntities: Entity[]; pageInfo?: QueryEntitiesResponse['pageInfo']; - count?: number; + totalItems?: number; }; /** @@ -226,7 +226,7 @@ export const EntityListProvider = ( backendEntities: response.items, entities: response.items.filter(entityFilter), pageInfo: response.pageInfo, - count: response.totalItems, + totalItems: response.totalItems, }); } } else { @@ -247,7 +247,7 @@ export const EntityListProvider = ( backendEntities: response.items, entities: response.items.filter(entityFilter), pageInfo: response.pageInfo, - count: response.totalItems, + totalItems: response.totalItems, }); } } @@ -272,7 +272,7 @@ export const EntityListProvider = ( appliedFilters: requestedFilters, backendEntities: response.items, entities, - count: entities.length, + totalItems: entities.length, }); } else { const entities = outputState.backendEntities.filter(entityFilter); @@ -280,7 +280,7 @@ export const EntityListProvider = ( appliedFilters: requestedFilters, backendEntities: outputState.backendEntities, entities, - count: entities.length, + totalItems: entities.length, }); } } @@ -361,7 +361,7 @@ export const EntityListProvider = ( loading, error, pageInfo, - count: outputState.count, + totalItems: outputState.totalItems, }), [outputState, updateFilters, queryParameters, loading, error, pageInfo], ); diff --git a/plugins/catalog-react/src/testUtils/providers.tsx b/plugins/catalog-react/src/testUtils/providers.tsx index ae99352f2c..6b88168207 100644 --- a/plugins/catalog-react/src/testUtils/providers.tsx +++ b/plugins/catalog-react/src/testUtils/providers.tsx @@ -71,7 +71,8 @@ export function MockEntityListContextProvider< loading: value?.loading ?? false, queryParameters: value?.queryParameters ?? defaultValues.queryParameters, error: value?.error, - count: (value?.entities ?? defaultValues.entities).length, + totalItems: + value?.totalItems ?? (value?.entities ?? defaultValues.entities).length, }), [value, defaultValues, filters, updateFilters], ); diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index a233499fde..8aa5b9e376 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -88,7 +88,7 @@ export const CatalogTable = (props: CatalogTableProps) => { } = props; const { isStarredEntity, toggleStarredEntity } = useStarredEntities(); const entityListContext = useEntityList(); - const { loading, error, entities, filters, pageInfo, count } = + const { loading, error, entities, filters, pageInfo, totalItems } = entityListContext; const enablePagination = !!pageInfo; @@ -176,7 +176,7 @@ export const CatalogTable = (props: CatalogTableProps) => { .filter(s => s) .join(' '); - const title = `${titleDisplay} (${count})`; + const title = `${titleDisplay} (${totalItems})`; const actions = props.actions || defaultActions; const options = { actionsColumnIndex: -1, diff --git a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx index 84f9beea7c..976cdff667 100644 --- a/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/PaginatedCatalogTable.test.tsx @@ -142,7 +142,7 @@ describe('PaginatedCatalogTable', () => { e.entity), - count: data.length, + totalItems: data.length, filters: { kind: new EntityKindFilter('component'), }, From 5d0112e1380a8265c7010542a3bcfda6e25ce3b8 Mon Sep 17 00:00:00 2001 From: aramissennyeydd Date: Sat, 2 Mar 2024 11:17:38 -0500 Subject: [PATCH 5/5] update changeset message Signed-off-by: aramissennyeydd --- .changeset/perfect-chefs-act.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/perfect-chefs-act.md b/.changeset/perfect-chefs-act.md index 99abbae19d..08da157dc7 100644 --- a/.changeset/perfect-chefs-act.md +++ b/.changeset/perfect-chefs-act.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-react': minor --- -Number of results is now directly added as the field `count` on `useEntityList`. +Number of results is now directly added as the field `totalItems` on `useEntityList`.