Skip to content

Commit

Permalink
[EuiInMemoryTable] Persist table rows per page and sort (elastic#198297)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebelga authored and CAWilson94 committed Dec 12, 2024
1 parent 8dac33d commit abc63f7
Show file tree
Hide file tree
Showing 57 changed files with 798 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const FinderApp = (props: {
<ContentClientProvider contentClient={props.contentClient}>
<I18nProvider>
<SavedObjectFinder
id="cmFinderApp"
showFilter={true}
services={{
savedObjectsTagging: props.savedObjectsTagging.getTaggingApi(),
Expand Down
20 changes: 20 additions & 0 deletions packages/content-management/table_list_view_table/src/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import React from 'react';
import { from } from 'rxjs';
import type { IStorage } from '@kbn/kibana-utils-plugin/public';

import type { Services, TagListProps } from './services';

Expand Down Expand Up @@ -149,3 +150,22 @@ export const getStoryArgTypes = () => ({
defaultValue: false,
},
});

export const localStorageMock = (): IStorage => {
let store: Record<string, unknown> = {};

return {
getItem: (key: string) => {
return store[key] || null;
},
setItem: (key: string, value: unknown) => {
store[key] = value;
},
clear() {
store = {};
},
removeItem(key: string) {
delete store[key];
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type { LocationDescriptor, History } from 'history';
import type { UserContentCommonSchema } from '@kbn/content-management-table-list-view-common';

import { WithServices } from './__jest__';
import { getTagList } from './mocks';
import { getTagList, localStorageMock } from './mocks';
import { TableListViewTable, type TableListViewTableProps } from './table_list_view_table';
import { getActions } from './table_list_view.test.helpers';
import type { Services } from './services';
Expand Down Expand Up @@ -335,6 +335,12 @@ describe('TableListView', () => {
const totalItems = 30;
const updatedAt = new Date().toISOString();

beforeEach(() => {
Object.defineProperty(window, 'localStorage', {
value: localStorageMock(),
});
});

const hits: UserContentCommonSchema[] = [...Array(totalItems)].map((_, i) => ({
id: `item${i}`,
type: 'dashboard',
Expand Down Expand Up @@ -429,6 +435,54 @@ describe('TableListView', () => {
expect(firstRowTitle).toBe('Item 20');
expect(lastRowTitle).toBe('Item 29');
});

test('should persist the number of rows in the table', async () => {
let testBed: TestBed;

const tableId = 'myTable';

await act(async () => {
testBed = await setup({
initialPageSize,
findItems: jest.fn().mockResolvedValue({ total: hits.length, hits: [...hits] }),
id: tableId,
});
});

{
const { component, table, find } = testBed!;
component.update();

const { tableCellsValues } = table.getMetaData('itemsInMemTable');
expect(tableCellsValues.length).toBe(20); // 20 by default

let storageValue = localStorage.getItem(`tablePersist:${tableId}`);
expect(storageValue).toBe(null);

find('tablePaginationPopoverButton').simulate('click');
find('tablePagination-10-rows').simulate('click');

storageValue = localStorage.getItem(`tablePersist:${tableId}`);
expect(storageValue).not.toBe(null);
expect(JSON.parse(storageValue!).pageSize).toBe(10);
}

// Mount a second table and verify that is shows only 10 rows
{
await act(async () => {
testBed = await setup({
initialPageSize,
findItems: jest.fn().mockResolvedValue({ total: hits.length, hits: [...hits] }),
id: tableId,
});
});

const { component, table } = testBed!;
component.update();
const { tableCellsValues } = table.getMetaData('itemsInMemTable');
expect(tableCellsValues.length).toBe(10); // 10 items this time
}
});
});

describe('column sorting', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
ContentInsightsProvider,
useContentInsightsServices,
} from '@kbn/content-management-content-insights-public';
import { useEuiTablePersist } from '@kbn/shared-ux-table-persist';

import {
Table,
Expand Down Expand Up @@ -443,7 +444,7 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
hasUpdatedAtMetadata,
hasCreatedByMetadata,
hasRecentlyAccessedMetadata,
pagination,
pagination: _pagination,
tableSort,
tableFilter,
} = state;
Expand Down Expand Up @@ -903,7 +904,7 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
[updateTableSortFilterAndPagination]
);

const onTableChange = useCallback(
const customOnTableChange = useCallback(
(criteria: CriteriaWithPagination<T>) => {
const data: {
sort?: State<T>['tableSort'];
Expand Down Expand Up @@ -1038,6 +1039,20 @@ function TableListViewTableComp<T extends UserContentCommonSchema>({
);
}, [entityName, fetchError]);

const { pageSize, onTableChange } = useEuiTablePersist({
tableId: listingId,
initialPageSize,
customOnTableChange,
pageSizeOptions: uniq([10, 20, 50, initialPageSize]).sort(),
});

const pagination = useMemo<Pagination>(() => {
return {
..._pagination,
pageSize,
};
}, [_pagination, pageSize]);

// ------------
// Effects
// ------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
"@kbn/content-management-user-profiles",
"@kbn/recently-accessed",
"@kbn/content-management-content-insights-public",
"@kbn/content-management-favorites-public"
"@kbn/content-management-favorites-public",
"@kbn/kibana-utils-plugin",
"@kbn/shared-ux-table-persist"
],
"exclude": [
"target/**/*"
Expand Down
39 changes: 13 additions & 26 deletions packages/kbn-alerts-ui-shared/src/alert_fields_table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import {
EuiTabbedContent,
EuiTabbedContentProps,
useEuiOverflowScroll,
EuiBasicTableColumn,
} from '@elastic/eui';
import { css } from '@emotion/react';
import React, { memo, useCallback, useMemo, useState } from 'react';
import React, { memo, useMemo } from 'react';
import { Alert } from '@kbn/alerting-types';
import { euiThemeVars } from '@kbn/ui-theme';
import { EuiBasicTableColumn } from '@elastic/eui/src/components/basic_table/basic_table';
import { useEuiTablePersist } from '@kbn/shared-ux-table-persist';

export const search = {
box: {
Expand Down Expand Up @@ -66,28 +67,6 @@ export const ScrollableFlyoutTabbedContent = (props: EuiTabbedContentProps) => (

const COUNT_PER_PAGE_OPTIONS = [25, 50, 100];

const useFieldBrowserPagination = () => {
const [pagination, setPagination] = useState<{ pageIndex: number }>({
pageIndex: 0,
});

const onTableChange = useCallback(({ page: { index } }: { page: { index: number } }) => {
setPagination({ pageIndex: index });
}, []);
const paginationTableProp = useMemo(
() => ({
...pagination,
pageSizeOptions: COUNT_PER_PAGE_OPTIONS,
}),
[pagination]
);

return {
onTableChange,
paginationTableProp,
};
};

type AlertField = Exclude<
{
[K in keyof Alert]: { key: K; value: Alert[K] };
Expand All @@ -111,7 +90,11 @@ export interface AlertFieldsTableProps {
* A paginated, filterable table to show alert object fields
*/
export const AlertFieldsTable = memo(({ alert, fields }: AlertFieldsTableProps) => {
const { onTableChange, paginationTableProp } = useFieldBrowserPagination();
const { pageSize, sorting, onTableChange } = useEuiTablePersist<AlertField>({
tableId: 'obltAlertFields',
initialPageSize: 25,
});

const items = useMemo(() => {
let _items = Object.entries(alert).map(
([key, value]) =>
Expand All @@ -131,7 +114,11 @@ export const AlertFieldsTable = memo(({ alert, fields }: AlertFieldsTableProps)
itemId="key"
columns={columns}
onTableChange={onTableChange}
pagination={paginationTableProp}
pagination={{
pageSize,
pageSizeOptions: COUNT_PER_PAGE_OPTIONS,
}}
sorting={sorting}
search={search}
css={css`
& .euiTableRow {
Expand Down
3 changes: 2 additions & 1 deletion packages/kbn-alerts-ui-shared/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@kbn/core-ui-settings-browser",
"@kbn/core-http-browser-mocks",
"@kbn/core-notifications-browser-mocks",
"@kbn/kibana-react-plugin"
"@kbn/kibana-react-plugin",
"@kbn/shared-ux-table-persist"
]
}
27 changes: 11 additions & 16 deletions packages/kbn-esql-editor/src/editor_footer/query_history.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ import {
EuiInMemoryTable,
EuiBasicTableColumn,
EuiButtonEmpty,
Criteria,
EuiButtonIcon,
CustomItemAction,
EuiCopy,
EuiToolTip,
euiScrollBarStyles,
} from '@elastic/eui';
import { css, Interpolation, Theme } from '@emotion/react';
import { useEuiTablePersist } from '@kbn/shared-ux-table-persist';
import { type QueryHistoryItem, getHistoryItems } from '../history_local_storage';
import { getReducedSpaceStyling, swapArrayElements } from './query_history_helpers';

Expand Down Expand Up @@ -212,8 +212,16 @@ export function QueryHistory({
}) {
const theme = useEuiTheme();
const scrollBarStyles = euiScrollBarStyles(theme);
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
const historyItems: QueryHistoryItem[] = getHistoryItems(sortDirection);

const { sorting, onTableChange } = useEuiTablePersist<QueryHistoryItem>({
tableId: 'esqlQueryHistory',
initialSort: {
field: 'timeRan',
direction: 'desc',
},
});

const historyItems: QueryHistoryItem[] = getHistoryItems(sorting.sort.direction);

const actions: Array<CustomItemAction<QueryHistoryItem>> = useMemo(() => {
return [
Expand Down Expand Up @@ -276,19 +284,6 @@ export function QueryHistory({
return getTableColumns(containerWidth, isOnReducedSpaceLayout, actions);
}, [actions, containerWidth, isOnReducedSpaceLayout]);

const onTableChange = ({ page, sort }: Criteria<QueryHistoryItem>) => {
if (sort) {
const { direction } = sort;
setSortDirection(direction);
}
};

const sorting = {
sort: {
field: 'timeRan',
direction: sortDirection,
},
};
const { euiTheme } = theme;
const extraStyling = isOnReducedSpaceLayout ? getReducedSpaceStyling() : '';

Expand Down
1 change: 1 addition & 0 deletions packages/kbn-esql-editor/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@kbn/fields-metadata-plugin",
"@kbn/esql-validation-autocomplete",
"@kbn/esql-utils",
"@kbn/shared-ux-table-persist",
],
"exclude": [
"target/**/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export const EventAnnotationGroupSavedObjectFinder = ({
) : (
<SavedObjectFinder
key="searchSavedObjectFinder"
id="eventAnnotationGroup"
fixedPageSize={fixedPageSize}
onChoose={(id, type, fullName, savedObject) => {
onChoose({ id, type, fullName, savedObject });
Expand Down
3 changes: 2 additions & 1 deletion packages/shared-ux/table_persist/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { useEuiTablePersist, DEFAULT_PAGE_SIZE_OPTIONS } from './src';
export { useEuiTablePersist, DEFAULT_PAGE_SIZE_OPTIONS, withEuiTablePersist } from './src';
export type { EuiTablePersistInjectedProps, EuiTablePersistPropsGetter, HOCProps } from './src';
6 changes: 6 additions & 0 deletions packages/shared-ux/table_persist/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@

export { useEuiTablePersist } from './use_table_persist';
export { DEFAULT_PAGE_SIZE_OPTIONS } from './constants';
export { withEuiTablePersist } from './table_persist_hoc';
export type {
EuiTablePersistInjectedProps,
EuiTablePersistPropsGetter,
HOCProps,
} from './table_persist_hoc';
Loading

0 comments on commit abc63f7

Please sign in to comment.