[RAM] Alert table reset pagination after filter (#157216)

## Summary

Fix https://github.com/elastic/kibana/issues/157133

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Xavier Mouligneau 2023-05-09 17:16:23 -04:00 committed by GitHub
parent 252d1a88d5
commit ee3d4e4744
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 144 additions and 12 deletions

View file

@ -219,6 +219,10 @@ const AlertsTableStateWithQueryProvider = ({
initialBrowserFields: propBrowserFields,
});
const onPageChange = useCallback((_pagination: RuleRegistrySearchRequestPagination) => {
setPagination(_pagination);
}, []);
const [
isLoading,
{
@ -236,6 +240,7 @@ const AlertsTableStateWithQueryProvider = ({
featureIds,
query,
pagination,
onPageChange,
runtimeMappings,
sort,
skip: false,
@ -261,10 +266,6 @@ const AlertsTableStateWithQueryProvider = ({
fetchCases
);
const onPageChange = useCallback((_pagination: RuleRegistrySearchRequestPagination) => {
setPagination(_pagination);
}, []);
const initialBulkActionsState = useReducer(bulkActionsReducer, {
rowSelection: new Map<number, RowSelectionState>(),
isAllSelected: false,
@ -318,7 +319,7 @@ const AlertsTableStateWithQueryProvider = ({
oldAlertsData,
onPageChange,
onSortChange,
pagination.pageIndex,
pagination,
refresh,
sort,
updatedAt,
@ -374,7 +375,7 @@ const AlertsTableStateWithQueryProvider = ({
memoizedCases,
columns,
flyoutSize,
pagination.pageSize,
pagination,
id,
leadingControlColumns,
showExpandToDetails,

View file

@ -11,6 +11,8 @@ import { act, renderHook } from '@testing-library/react-hooks';
import { useFetchAlerts, FetchAlertsArgs, FetchAlertResp } from './use_fetch_alerts';
import { useKibana } from '../../../../common/lib/kibana';
import { IKibanaSearchResponse } from '@kbn/data-plugin/public';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { useState } from 'react';
jest.mock('../../../../common/lib/kibana');
@ -88,6 +90,7 @@ const expectedResponse: FetchAlertResp = {
describe('useFetchAlerts', () => {
let clock: sinon.SinonFakeTimers;
const onPageChangeMock = jest.fn();
const args: FetchAlertsArgs = {
featureIds: ['siem'],
fields: [
@ -101,6 +104,7 @@ describe('useFetchAlerts', () => {
pageIndex: 0,
pageSize: 10,
},
onPageChange: onPageChangeMock,
sort: [],
skip: false,
};
@ -474,4 +478,75 @@ describe('useFetchAlerts', () => {
},
]);
});
it('reset pagination when query is used', async () => {
const useWrapperHook = ({ query }: { query: Pick<QueryDslQueryContainer, 'bool' | 'ids'> }) => {
const [pagination, setPagination] = useState({ pageIndex: 5, pageSize: 10 });
const handlePagination = (newPagination: { pageIndex: number; pageSize: number }) => {
onPageChangeMock(newPagination);
setPagination(newPagination);
};
const result = useFetchAlerts({
...args,
pagination,
onPageChange: handlePagination,
query,
});
return result;
};
const { rerender } = renderHook(
({ initialValue }) =>
useWrapperHook({
query: initialValue,
}),
{
initialProps: { initialValue: {} },
}
);
expect(dataSearchMock).lastCalledWith(
{
featureIds: args.featureIds,
fields: [...args.fields],
pagination: {
pageIndex: 5,
pageSize: 10,
},
query: {},
sort: args.sort,
},
{ abortSignal: expect.anything(), strategy: 'privateRuleRegistryAlertsSearchStrategy' }
);
rerender({
initialValue: {
ids: {
values: ['alert-id-1'],
},
},
});
expect(dataSearchMock).lastCalledWith(
{
featureIds: args.featureIds,
fields: [...args.fields],
pagination: {
pageIndex: 0,
pageSize: 10,
},
query: {
ids: {
values: ['alert-id-1'],
},
},
sort: args.sort,
},
{ abortSignal: expect.anything(), strategy: 'privateRuleRegistryAlertsSearchStrategy' }
);
expect(onPageChangeMock).lastCalledWith({
pageIndex: 0,
pageSize: 10,
});
});
});

View file

@ -15,6 +15,7 @@ import { Subscription } from 'rxjs';
import { isCompleteResponse, isErrorResponse } from '@kbn/data-plugin/common';
import type {
RuleRegistrySearchRequest,
RuleRegistrySearchRequestPagination,
RuleRegistrySearchResponse,
} from '@kbn/rule-registry-plugin/common/search_strategy';
import type {
@ -36,12 +37,13 @@ export interface FetchAlertsArgs {
pageIndex: number;
pageSize: number;
};
onPageChange: (pagination: RuleRegistrySearchRequestPagination) => void;
runtimeMappings?: MappingRuntimeFields;
sort: SortCombinations[];
skip: boolean;
}
type AlertRequest = Omit<FetchAlertsArgs, 'featureIds' | 'skip'>;
type AlertRequest = Omit<FetchAlertsArgs, 'featureIds' | 'skip' | 'onPageChange'>;
type Refetch = () => void;
@ -67,7 +69,7 @@ export interface FetchAlertResp {
type AlertResponseState = Omit<FetchAlertResp, 'getInspectQuery' | 'refetch'>;
interface AlertStateReducer {
loading: boolean;
request: Omit<FetchAlertsArgs, 'skip'>;
request: Omit<FetchAlertsArgs, 'skip' | 'onPageChange'>;
response: AlertResponseState;
}
@ -81,7 +83,7 @@ type AlertActions =
ecsAlertsData: unknown[];
}
| { type: 'resetPagination' }
| { type: 'request'; request: Omit<FetchAlertsArgs, 'skip'> };
| { type: 'request'; request: Omit<FetchAlertsArgs, 'skip' | 'onPageChange'> };
const initialAlertState: AlertStateReducer = {
loading: false,
@ -146,6 +148,7 @@ export type UseFetchAlerts = ({
fields,
query,
pagination,
onPageChange,
runtimeMappings,
skip,
sort,
@ -155,6 +158,7 @@ const useFetchAlerts = ({
fields,
query,
pagination,
onPageChange,
runtimeMappings,
skip,
sort,
@ -279,6 +283,9 @@ const useFetchAlerts = ({
[skip, data, featureIds, query, fields]
);
// FUTURE ENGINEER
// This useEffect is only to fetch the alert when these props below changed
// fields, pagination, sort, runtimeMappings
useEffect(() => {
if (featureIds.length === 0) {
return;
@ -287,7 +294,7 @@ const useFetchAlerts = ({
featureIds,
fields,
pagination,
query,
query: prevAlertRequest.current?.query ?? {},
runtimeMappings,
sort,
};
@ -300,7 +307,37 @@ const useFetchAlerts = ({
request: newAlertRequest,
});
}
}, [featureIds, fields, pagination, query, sort, runtimeMappings]);
}, [featureIds, fields, pagination, sort, runtimeMappings]);
// FUTURE ENGINEER
// This useEffect is only to fetch the alert when query props changed
// because we want to reset the pageIndex of pagination to 0
useEffect(() => {
if (featureIds.length === 0 || !prevAlertRequest.current) {
return;
}
const resetPagination = {
pageIndex: 0,
pageSize: prevAlertRequest.current?.pagination?.pageSize ?? 50,
};
const newAlertRequest = {
...prevAlertRequest.current,
featureIds,
pagination: resetPagination,
query,
};
if (
(newAlertRequest?.fields ?? []).length > 0 &&
!deepEqual(newAlertRequest.query, prevAlertRequest.current.query)
) {
dispatch({
type: 'request',
request: newAlertRequest,
});
onPageChange(resetPagination);
}
}, [featureIds, onPageChange, query]);
useEffect(() => {
if (alertRequest.featureIds.length > 0 && !deepEqual(alertRequest, prevAlertRequest.current)) {

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useCallback, useContext, useState } from 'react';
import { useCallback, useContext, useEffect, useState } from 'react';
import { RuleRegistrySearchRequestPagination } from '@kbn/rule-registry-plugin/common';
import { BulkActionsVerbs } from '../../../../types';
import { BulkActionsContext } from '../bulk_actions/context';
@ -75,6 +75,25 @@ export function usePagination({ onPageChange, pageIndex, pageSize }: PaginationP
[onChangePageIndex, pagination.pageIndex, pagination.pageSize]
);
useEffect(() => {
setPagination((prevPagination) => {
const newPagination = { ...prevPagination };
let updated = false;
if (prevPagination.pageIndex !== pageIndex) {
updated = true;
newPagination.pageIndex = pageIndex;
}
if (prevPagination.pageSize !== pageSize) {
updated = true;
newPagination.pageSize = pageSize;
}
if (updated === true) {
return newPagination;
}
return prevPagination;
});
}, [pageIndex, pageSize]);
return {
pagination,
onChangePageSize,