Merge pull request #22527 from sennyeya/better-catalog-pagination-info
feat(catalog): Add a title to the PaginatedCatalogTable.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-react': minor
|
||||
---
|
||||
|
||||
Number of results is now directly added as the field `totalItems` on `useEntityList`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog': minor
|
||||
---
|
||||
|
||||
Adds a title to the `PaginatedCatalogTable` for better visibility on what you're viewing.
|
||||
@@ -306,6 +306,7 @@ export type EntityListContextProps<
|
||||
next?: () => void;
|
||||
prev?: () => void;
|
||||
};
|
||||
totalItems?: number;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -235,6 +235,7 @@ describe('<EntityListProvider />', () => {
|
||||
await waitFor(() => {
|
||||
expect(result.current.entities.length).toBe(1);
|
||||
});
|
||||
expect(result.current.totalItems).toBe(1);
|
||||
|
||||
await expect(() =>
|
||||
waitFor(() => {
|
||||
@@ -251,6 +252,7 @@ describe('<EntityListProvider />', () => {
|
||||
await waitFor(() => {
|
||||
expect(result.current.backendEntities.length).toBeGreaterThan(0);
|
||||
});
|
||||
expect(result.current.totalItems).toBe(2);
|
||||
expect(result.current.backendEntities.length).toBe(2);
|
||||
expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -276,6 +278,8 @@ describe('<EntityListProvider />', () => {
|
||||
});
|
||||
expect(result.current.backendEntities.length).toBe(2);
|
||||
|
||||
expect(result.current.totalItems).toBe(2);
|
||||
|
||||
mockCatalogApi.getEntities!.mockRejectedValueOnce('error');
|
||||
act(() => {
|
||||
result.current.updateFilters({ kind: new EntityKindFilter('api') });
|
||||
@@ -455,6 +459,8 @@ describe('<EntityListProvider pagination />', () => {
|
||||
orderFields,
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.totalItems).toBe(10);
|
||||
});
|
||||
|
||||
it('returns an error on catalogApi failure', async () => {
|
||||
|
||||
@@ -108,6 +108,8 @@ export type EntityListContextProps<
|
||||
next?: () => void;
|
||||
prev?: () => void;
|
||||
};
|
||||
|
||||
totalItems?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -124,6 +126,7 @@ type OutputState<EntityFilters extends DefaultEntityFilters> = {
|
||||
entities: Entity[];
|
||||
backendEntities: Entity[];
|
||||
pageInfo?: QueryEntitiesResponse['pageInfo'];
|
||||
totalItems?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -223,6 +226,7 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(
|
||||
backendEntities: response.items,
|
||||
entities: response.items.filter(entityFilter),
|
||||
pageInfo: response.pageInfo,
|
||||
totalItems: response.totalItems,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -243,6 +247,7 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(
|
||||
backendEntities: response.items,
|
||||
entities: response.items.filter(entityFilter),
|
||||
pageInfo: response.pageInfo,
|
||||
totalItems: response.totalItems,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -262,16 +267,20 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(
|
||||
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,
|
||||
totalItems: entities.length,
|
||||
});
|
||||
} else {
|
||||
const entities = outputState.backendEntities.filter(entityFilter);
|
||||
setOutputState({
|
||||
appliedFilters: requestedFilters,
|
||||
backendEntities: outputState.backendEntities,
|
||||
entities: outputState.backendEntities.filter(entityFilter),
|
||||
entities,
|
||||
totalItems: entities.length,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -352,6 +361,7 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(
|
||||
loading,
|
||||
error,
|
||||
pageInfo,
|
||||
totalItems: outputState.totalItems,
|
||||
}),
|
||||
[outputState, updateFilters, queryParameters, loading, error, pageInfo],
|
||||
);
|
||||
|
||||
@@ -71,6 +71,8 @@ export function MockEntityListContextProvider<
|
||||
loading: value?.loading ?? false,
|
||||
queryParameters: value?.queryParameters ?? defaultValues.queryParameters,
|
||||
error: value?.error,
|
||||
totalItems:
|
||||
value?.totalItems ?? (value?.entities ?? defaultValues.entities).length,
|
||||
}),
|
||||
[value, defaultValues, filters, updateFilters],
|
||||
);
|
||||
|
||||
@@ -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, totalItems } =
|
||||
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} (${totalItems})`;
|
||||
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}
|
||||
|
||||
@@ -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(
|
||||
<MockEntityListContextProvider
|
||||
value={{
|
||||
entities: data.map(e => e.entity),
|
||||
totalItems: data.length,
|
||||
filters: {
|
||||
kind: new EntityKindFilter('component'),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<PaginatedCatalogTable
|
||||
data={data}
|
||||
columns={columns}
|
||||
next={undefined}
|
||||
title="My title"
|
||||
/>
|
||||
</MockEntityListContextProvider>,
|
||||
);
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 (
|
||||
<Table
|
||||
title={isLoading ? '' : title}
|
||||
columns={columns}
|
||||
data={data}
|
||||
options={{
|
||||
|
||||
Reference in New Issue
Block a user