mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution] [Field Browser] Prevent pagination reset on field selection (#131714)
* prevent pagination reset on selection * sorting controls Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
57597f7617
commit
818f5e63b2
2 changed files with 167 additions and 43 deletions
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { render, RenderResult } from '@testing-library/react';
|
||||
import { mockBrowserFields, TestProviders } from '../../../../mock';
|
||||
import { tGridActions } from '../../../../store/t_grid';
|
||||
import { defaultColumnHeaderType } from '../../body/column_headers/default_headers';
|
||||
|
@ -155,50 +155,117 @@ describe('FieldTable', () => {
|
|||
expect(checkbox).toHaveAttribute('checked');
|
||||
});
|
||||
|
||||
it('should dispatch remove column action on field unchecked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
<FieldTable
|
||||
{...defaultProps}
|
||||
selectedCategoryIds={['base']}
|
||||
columnHeaders={columnHeaders}
|
||||
filteredBrowserFields={{ base: { fields: { [timestampFieldId]: timestampField } } }}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
describe('selection', () => {
|
||||
it('should dispatch remove column action on field unchecked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
<FieldTable
|
||||
{...defaultProps}
|
||||
selectedCategoryIds={['base']}
|
||||
columnHeaders={columnHeaders}
|
||||
filteredBrowserFields={{ base: { fields: { [timestampFieldId]: timestampField } } }}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
result.getByTestId(`field-${timestampFieldId}-checkbox`).click();
|
||||
result.getByTestId(`field-${timestampFieldId}-checkbox`).click();
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
tGridActions.removeColumn({ id: timelineId, columnId: timestampFieldId })
|
||||
);
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
tGridActions.removeColumn({ id: timelineId, columnId: timestampFieldId })
|
||||
);
|
||||
});
|
||||
|
||||
it('should dispatch upsert column action on field checked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
<FieldTable
|
||||
{...defaultProps}
|
||||
selectedCategoryIds={['base']}
|
||||
filteredBrowserFields={{ base: { fields: { [timestampFieldId]: timestampField } } }}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
result.getByTestId(`field-${timestampFieldId}-checkbox`).click();
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
tGridActions.upsertColumn({
|
||||
id: timelineId,
|
||||
column: {
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: timestampFieldId,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
index: 1,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch upsert column action on field checked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
describe('pagination', () => {
|
||||
const isAtFirstPage = (result: RenderResult) =>
|
||||
result.getByTestId('pagination-button-0').classList.contains('euiPaginationButton-isActive');
|
||||
|
||||
const changePage = (result: RenderResult) => {
|
||||
result.getByTestId('pagination-button-1').click();
|
||||
};
|
||||
|
||||
const defaultPaginationProps: FieldTableProps = {
|
||||
...defaultProps,
|
||||
filteredBrowserFields: mockBrowserFields,
|
||||
};
|
||||
|
||||
it('should paginate on page clicked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
<FieldTable {...defaultPaginationProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(isAtFirstPage(result)).toBeTruthy();
|
||||
|
||||
changePage(result);
|
||||
|
||||
expect(isAtFirstPage(result)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not reset on field checked', () => {
|
||||
const result = render(
|
||||
<TestProviders>
|
||||
<FieldTable {...defaultPaginationProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
changePage(result);
|
||||
|
||||
result.getAllByRole('checkbox').at(0)?.click();
|
||||
expect(mockDispatch).toHaveBeenCalled(); // assert some field has been selected
|
||||
|
||||
expect(isAtFirstPage(result)).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should reset on filter change', () => {
|
||||
const result = render(
|
||||
<FieldTable
|
||||
{...defaultProps}
|
||||
selectedCategoryIds={['base']}
|
||||
filteredBrowserFields={{ base: { fields: { [timestampFieldId]: timestampField } } }}
|
||||
{...defaultPaginationProps}
|
||||
selectedCategoryIds={['destination', 'event', 'client', 'agent', 'host']}
|
||||
/>,
|
||||
{ wrapper: TestProviders }
|
||||
);
|
||||
|
||||
changePage(result);
|
||||
expect(isAtFirstPage(result)).toBeFalsy();
|
||||
|
||||
result.rerender(
|
||||
<FieldTable
|
||||
{...defaultPaginationProps}
|
||||
selectedCategoryIds={['destination', 'event', 'client', 'agent']}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
);
|
||||
|
||||
result.getByTestId(`field-${timestampFieldId}-checkbox`).click();
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
tGridActions.upsertColumn({
|
||||
id: timelineId,
|
||||
column: {
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: timestampFieldId,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
index: 1,
|
||||
})
|
||||
);
|
||||
expect(isAtFirstPage(result)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiInMemoryTable } from '@elastic/eui';
|
||||
import { EuiInMemoryTable, Pagination, Direction } from '@elastic/eui';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { BrowserFields, ColumnHeaderOptions } from '../../../../../common';
|
||||
import { getColumnHeader, getFieldColumns, getFieldItems, isActionsColumn } from './field_items';
|
||||
|
@ -16,6 +16,11 @@ import { tGridActions } from '../../../../store/t_grid';
|
|||
import type { GetFieldTableColumns } from '../../../../../common/types/fields_browser';
|
||||
import { FieldTableHeader } from './field_table_header';
|
||||
|
||||
const DEFAULT_SORTING: { field: string; direction: Direction } = {
|
||||
field: '',
|
||||
direction: 'asc',
|
||||
} as const;
|
||||
|
||||
export interface FieldTableProps {
|
||||
timelineId: string;
|
||||
columnHeaders: ColumnHeaderOptions[];
|
||||
|
@ -69,6 +74,12 @@ const FieldTableComponent: React.FC<FieldTableProps> = ({
|
|||
timelineId,
|
||||
onHide,
|
||||
}) => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
|
||||
const [sortField, setSortField] = useState<string>(DEFAULT_SORTING.field);
|
||||
const [sortDirection, setSortDirection] = useState<Direction>(DEFAULT_SORTING.direction);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const fieldItems = useMemo(
|
||||
|
@ -103,6 +114,51 @@ const FieldTableComponent: React.FC<FieldTableProps> = ({
|
|||
[columnHeaders, dispatch, timelineId]
|
||||
);
|
||||
|
||||
/**
|
||||
* Pagination controls
|
||||
*/
|
||||
const pagination: Pagination = useMemo(
|
||||
() => ({
|
||||
pageIndex,
|
||||
pageSize,
|
||||
totalItemCount: fieldItems.length,
|
||||
pageSizeOptions: [10, 25, 50],
|
||||
}),
|
||||
[fieldItems.length, pageIndex, pageSize]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// Resets the pagination when some filter has changed, consequently, the number of fields is different
|
||||
setPageIndex(0);
|
||||
}, [fieldItems.length]);
|
||||
|
||||
/**
|
||||
* Sorting controls
|
||||
*/
|
||||
const sorting = useMemo(
|
||||
() => ({
|
||||
sort: {
|
||||
field: sortField,
|
||||
direction: sortDirection,
|
||||
},
|
||||
}),
|
||||
[sortDirection, sortField]
|
||||
);
|
||||
|
||||
const onTableChange = useCallback(({ page, sort = DEFAULT_SORTING }) => {
|
||||
const { index, size } = page;
|
||||
const { field, direction } = sort;
|
||||
|
||||
setPageIndex(index);
|
||||
setPageSize(size);
|
||||
|
||||
setSortField(field);
|
||||
setSortDirection(direction);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Process columns
|
||||
*/
|
||||
const columns = useMemo(
|
||||
() => getFieldColumns({ highlight: searchInput, onToggleColumn, getFieldTableColumns, onHide }),
|
||||
[onToggleColumn, searchInput, getFieldTableColumns, onHide]
|
||||
|
@ -124,9 +180,10 @@ const FieldTableComponent: React.FC<FieldTableProps> = ({
|
|||
items={fieldItems}
|
||||
itemId="name"
|
||||
columns={columns}
|
||||
pagination={true}
|
||||
sorting={true}
|
||||
pagination={pagination}
|
||||
sorting={sorting}
|
||||
hasActions={hasActions}
|
||||
onChange={onTableChange}
|
||||
compressed
|
||||
/>
|
||||
</TableContainer>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue