diff --git a/docs/data/data-grid/filtering/FilteringWithPageReset.js b/docs/data/data-grid/filtering/FilteringWithPageReset.js new file mode 100644 index 0000000000000..fe1819b535bc1 --- /dev/null +++ b/docs/data/data-grid/filtering/FilteringWithPageReset.js @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { DataGrid, GridToolbar } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin']; + +export default function FilteringWithPageReset() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + visibleFields: VISIBLE_FIELDS, + rowLength: 100, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/filtering/FilteringWithPageReset.tsx b/docs/data/data-grid/filtering/FilteringWithPageReset.tsx new file mode 100644 index 0000000000000..fe1819b535bc1 --- /dev/null +++ b/docs/data/data-grid/filtering/FilteringWithPageReset.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { DataGrid, GridToolbar } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin']; + +export default function FilteringWithPageReset() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + visibleFields: VISIBLE_FIELDS, + rowLength: 100, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/filtering/FilteringWithPageReset.tsx.preview b/docs/data/data-grid/filtering/FilteringWithPageReset.tsx.preview new file mode 100644 index 0000000000000..72c3e0f9e6081 --- /dev/null +++ b/docs/data/data-grid/filtering/FilteringWithPageReset.tsx.preview @@ -0,0 +1,12 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/filtering/index.md b/docs/data/data-grid/filtering/index.md index 3a1eff48b1349..35cacd8dc164c 100644 --- a/docs/data/data-grid/filtering/index.md +++ b/docs/data/data-grid/filtering/index.md @@ -147,6 +147,14 @@ const columns = [ {{"demo": "ReadOnlyFilters.js", "bg": "inline", "defaultCodeOpen": false}} +## Reset page on filtering + +By default, the user stays on the same page after a filter is applied, unless the new row count indicates that that page doesn't exist anymore. +In that case, the user is sent to the last page as defined by the new row count. +To send the user back to the first page when a new filter is applied, use the `resetPageOnSortFilter` prop. + +{{"demo": "FilteringWithPageReset.js", "bg": "inline", "defaultCodeOpen": false}} + ## Ignore diacritics (accents) You can ignore diacritics (accents) when filtering the rows. See [Quick filter - Ignore diacritics (accents)](/x/react-data-grid/filtering/quick-filter/#ignore-diacritics-accents). diff --git a/docs/data/data-grid/filtering/server-side.md b/docs/data/data-grid/filtering/server-side.md index b579126d9049d..91e81bed48828 100644 --- a/docs/data/data-grid/filtering/server-side.md +++ b/docs/data/data-grid/filtering/server-side.md @@ -8,6 +8,10 @@ The example below demonstrates how to achieve server-side filtering. {{"demo": "ServerFilterGrid.js", "bg": "inline"}} +:::success +You can combine server-side filtering with [server-side sorting](/x/react-data-grid/sorting/#server-side-sorting) and [server-side pagination](/x/react-data-grid/pagination/#server-side-pagination) to avoid fetching more data than needed, since it's already processed outside of the Data Grid. +::: + ## API - [DataGrid](/x/api/data-grid/data-grid/) diff --git a/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.js b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.js new file mode 100644 index 0000000000000..24c7294a12c62 --- /dev/null +++ b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.js @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { createFakeServer } from '@mui/x-data-grid-generator'; + +const SERVER_OPTIONS = { + useCursorPagination: false, +}; + +const { useQuery, ...data } = createFakeServer({}, SERVER_OPTIONS); + +export default function ServerPaginationFilterSortGrid() { + const [paginationModel, setPaginationModel] = React.useState({ + page: 0, + pageSize: 5, + }); + const [sortModel, setSortModel] = React.useState([]); + const [filterModel, setFilterModel] = React.useState({ + items: [], + }); + const queryOptions = React.useMemo( + () => ({ ...paginationModel, sortModel, filterModel }), + [paginationModel, sortModel, filterModel], + ); + const { isLoading, rows, pageInfo } = useQuery(queryOptions); + + // Some API clients return undefined while loading + // Following lines are here to prevent `rowCount` from being undefined during the loading + const rowCountRef = React.useRef(pageInfo?.totalRowCount || 0); + + const rowCount = React.useMemo(() => { + if (pageInfo?.totalRowCount !== undefined) { + rowCountRef.current = pageInfo.totalRowCount; + } + return rowCountRef.current; + }, [pageInfo?.totalRowCount]); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx new file mode 100644 index 0000000000000..37a361d6424ca --- /dev/null +++ b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import { DataGrid, GridSortModel, GridFilterModel } from '@mui/x-data-grid'; +import { createFakeServer } from '@mui/x-data-grid-generator'; + +const SERVER_OPTIONS = { + useCursorPagination: false, +}; + +const { useQuery, ...data } = createFakeServer({}, SERVER_OPTIONS); + +export default function ServerPaginationFilterSortGrid() { + const [paginationModel, setPaginationModel] = React.useState({ + page: 0, + pageSize: 5, + }); + const [sortModel, setSortModel] = React.useState([]); + const [filterModel, setFilterModel] = React.useState({ + items: [], + }); + const queryOptions = React.useMemo( + () => ({ ...paginationModel, sortModel, filterModel }), + [paginationModel, sortModel, filterModel], + ); + const { isLoading, rows, pageInfo } = useQuery(queryOptions); + + // Some API clients return undefined while loading + // Following lines are here to prevent `rowCount` from being undefined during the loading + const rowCountRef = React.useRef(pageInfo?.totalRowCount || 0); + + const rowCount = React.useMemo(() => { + if (pageInfo?.totalRowCount !== undefined) { + rowCountRef.current = pageInfo.totalRowCount; + } + return rowCountRef.current; + }, [pageInfo?.totalRowCount]); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx.preview b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx.preview new file mode 100644 index 0000000000000..3a9a0aa25687f --- /dev/null +++ b/docs/data/data-grid/pagination/ServerPaginationFilterSortGrid.tsx.preview @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/pagination/pagination.md b/docs/data/data-grid/pagination/pagination.md index 4e3dbaba85050..005379f59f5a8 100644 --- a/docs/data/data-grid/pagination/pagination.md +++ b/docs/data/data-grid/pagination/pagination.md @@ -103,6 +103,14 @@ By default, the pagination is handled on the client. This means you have to give the rows of all pages to the Data Grid. If your dataset is too big, and you want to fetch the pages on demand, you can use server-side pagination. +:::warning +If you enable server-side pagination with no other server-side features, then the Data Grid will only be provided with partial data for filtering and sorting. +To be able to work with the entire dataset, you must also implement [server-side filtering](/x/react-data-grid/filtering/server-side/) and [server-side sorting](/x/react-data-grid/sorting/#server-side-sorting). +The demo below does exactly that. +::: + +{{"demo": "ServerPaginationFilterSortGrid.js", "bg": "inline"}} + In general, the server-side pagination could be categorized into two types: - Index-based pagination diff --git a/docs/data/data-grid/sorting/SortingWithPageReset.js b/docs/data/data-grid/sorting/SortingWithPageReset.js new file mode 100644 index 0000000000000..2ddb05e5b2047 --- /dev/null +++ b/docs/data/data-grid/sorting/SortingWithPageReset.js @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin']; + +export default function SortingWithPageReset() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + visibleFields: VISIBLE_FIELDS, + rowLength: 100, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/sorting/SortingWithPageReset.tsx b/docs/data/data-grid/sorting/SortingWithPageReset.tsx new file mode 100644 index 0000000000000..2ddb05e5b2047 --- /dev/null +++ b/docs/data/data-grid/sorting/SortingWithPageReset.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { DataGrid } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const VISIBLE_FIELDS = ['name', 'rating', 'country', 'dateCreated', 'isAdmin']; + +export default function SortingWithPageReset() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + visibleFields: VISIBLE_FIELDS, + rowLength: 100, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/sorting/SortingWithPageReset.tsx.preview b/docs/data/data-grid/sorting/SortingWithPageReset.tsx.preview new file mode 100644 index 0000000000000..b0086d4b64c1d --- /dev/null +++ b/docs/data/data-grid/sorting/SortingWithPageReset.tsx.preview @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/sorting/sorting.md b/docs/data/data-grid/sorting/sorting.md index eb6c4f62f8bd2..18cd30a300f77 100644 --- a/docs/data/data-grid/sorting/sorting.md +++ b/docs/data/data-grid/sorting/sorting.md @@ -91,6 +91,13 @@ In the following demo, the `firstName` column is not sortable by the default gri {{"demo": "ReadOnlySortingGrid.js", "bg": "inline", "defaultCodeOpen": false}} +## Reset page on sorting + +By default, sorting does not change the current page. +To send the user back to the first page when a new sort is applied, use the `resetPageOnSortFilter` prop. + +{{"demo": "SortingWithPageReset.js", "bg": "inline", "defaultCodeOpen": false}} + ## Custom comparator A comparator determines how two cell values should be sorted. @@ -164,6 +171,10 @@ Sorting can be run server-side by setting the `sortingMode` prop to `server`, an {{"demo": "ServerSortingGrid.js", "bg": "inline"}} +:::success +You can combine server-side sorting with [server-side filtering](/x/react-data-grid/filtering/server-side/) and [server-side pagination](/x/react-data-grid/pagination/#server-side-pagination) to avoid fetching more data than needed, since it's already processed outside of the Data Grid. +::: + ## apiRef :::warning diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index b34b83891a813..b117131e808ce 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -569,6 +569,7 @@ "returned": "Promise | R" } }, + "resetPageOnSortFilter": { "type": { "name": "bool" }, "default": "false" }, "resizeThrottleMs": { "type": { "name": "number" }, "default": "60" }, "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 9feee5d8324c6..805deee96fd73 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -512,6 +512,7 @@ "returned": "Promise | R" } }, + "resetPageOnSortFilter": { "type": { "name": "bool" }, "default": "false" }, "resizeThrottleMs": { "type": { "name": "number" }, "default": "60" }, "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 2b6f2223e509a..d519e11f16c4f 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -430,6 +430,7 @@ "returned": "Promise | R" } }, + "resetPageOnSortFilter": { "type": { "name": "bool" }, "default": "false" }, "resizeThrottleMs": { "type": { "name": "number" }, "default": "60" }, "rowBufferPx": { "type": { "name": "number" }, "default": "150" }, "rowCount": { "type": { "name": "number" } }, diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index f7798397bc2cd..8ccbedd12d502 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -599,6 +599,9 @@ "Promise | R": "The final values to update the row." } }, + "resetPageOnSortFilter": { + "description": "If true, the page is set to 0 after each sorting or filtering. This prop will be removed in the next major version and resetting the page will become the default behavior." + }, "resizeThrottleMs": { "description": "The milliseconds throttle delay for resizing the grid." }, "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index 5c0b268588d85..c430141f37394 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -545,6 +545,9 @@ "Promise | R": "The final values to update the row." } }, + "resetPageOnSortFilter": { + "description": "If true, the page is set to 0 after each sorting or filtering. This prop will be removed in the next major version and resetting the page will become the default behavior." + }, "resizeThrottleMs": { "description": "The milliseconds throttle delay for resizing the grid." }, "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 4e418523c65cc..47cdd9d6eb850 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -447,6 +447,9 @@ "Promise | R": "The final values to update the row." } }, + "resetPageOnSortFilter": { + "description": "If true, the page is set to 0 after each sorting or filtering. This prop will be removed in the next major version and resetting the page will become the default behavior." + }, "resizeThrottleMs": { "description": "The milliseconds throttle delay for resizing the grid." }, "rowBufferPx": { "description": "Row region in pixels to render before/after the viewport" }, "rowCount": { diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 9e7a59ee74c6b..4082fe51a89bc 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -906,6 +906,12 @@ DataGridPremiumRaw.propTypes = { * @returns {Promise | R} The final values to update the row. */ processRowUpdate: PropTypes.func, + /** + * If `true`, the page is set to 0 after each sorting or filtering. + * This prop will be removed in the next major version and resetting the page will become the default behavior. + * @default false + */ + resetPageOnSortFilter: PropTypes.bool, /** * The milliseconds throttle delay for resizing the grid. * @default 60 diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index d53b3366730e1..135bbaa59bfba 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -823,6 +823,12 @@ DataGridProRaw.propTypes = { * @returns {Promise | R} The final values to update the row. */ processRowUpdate: PropTypes.func, + /** + * If `true`, the page is set to 0 after each sorting or filtering. + * This prop will be removed in the next major version and resetting the page will become the default behavior. + * @default false + */ + resetPageOnSortFilter: PropTypes.bool, /** * The milliseconds throttle delay for resizing the grid. * @default 60 diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index cf33110f1698d..8bc403c0d678c 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -674,6 +674,12 @@ DataGridRaw.propTypes = { * @returns {Promise | R} The final values to update the row. */ processRowUpdate: PropTypes.func, + /** + * If `true`, the page is set to 0 after each sorting or filtering. + * This prop will be removed in the next major version and resetting the page will become the default behavior. + * @default false + */ + resetPageOnSortFilter: PropTypes.bool, /** * The milliseconds throttle delay for resizing the grid. * @default 60 diff --git a/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts b/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts index df9cfed47780e..aa8dfa8071bee 100644 --- a/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts +++ b/packages/x-data-grid/src/constants/dataGridPropsDefaultValues.ts @@ -44,6 +44,7 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { pageSizeOptions: [25, 50, 100], pagination: false, paginationMode: 'client', + resetPageOnSortFilter: false, resizeThrottleMs: 60, rowBufferPx: 150, rowHeight: 52, diff --git a/packages/x-data-grid/src/hooks/features/pagination/useGridPaginationModel.ts b/packages/x-data-grid/src/hooks/features/pagination/useGridPaginationModel.ts index fca83c2b2f5dd..b08a15622e859 100644 --- a/packages/x-data-grid/src/hooks/features/pagination/useGridPaginationModel.ts +++ b/packages/x-data-grid/src/hooks/features/pagination/useGridPaginationModel.ts @@ -5,6 +5,11 @@ import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { GridPaginationModelApi, GridPaginationState } from './gridPaginationInterfaces'; import { GridEventListener } from '../../../models/events'; import { GridPaginationModel } from '../../../models/gridPaginationProps'; +import { GridFilterModel } from '../../../models/gridFilterModel'; +import { + gridFilterModelSelector, + gridFilterActiveItemsSelector, +} from '../filter/gridFilterSelector'; import { gridDensityFactorSelector } from '../density'; import { useGridLogger, @@ -12,6 +17,7 @@ import { useGridApiMethod, useGridApiEventHandler, } from '../../utils'; +import { isDeepEqual, runIf } from '../../../utils/utils'; import { GridPipeProcessor, useGridRegisterPipeProcessor } from '../../core/pipeProcessing'; import { gridPageCountSelector, gridPaginationModelSelector } from './gridPaginationSelector'; import { @@ -67,11 +73,13 @@ export const useGridPaginationModel = ( | 'pagination' | 'signature' | 'rowHeight' + | 'resetPageOnSortFilter' >, ) => { const logger = useGridLogger(apiRef, 'useGridPaginationModel'); - const densityFactor = useGridSelector(apiRef, gridDensityFactorSelector); + const previousFilterModel = React.useRef(gridFilterModelSelector(apiRef)); + const rowHeight = Math.floor(props.rowHeight * densityFactor); apiRef.current.registerControlState({ stateId: 'paginationModel', @@ -242,7 +250,12 @@ export const useGridPaginationModel = ( if (newRowCount == null) { return; } + const paginationModel = gridPaginationModelSelector(apiRef); + if (paginationModel.page === 0) { + return; + } + const pageCount = gridPageCountSelector(apiRef); if (paginationModel.page > pageCount - 1) { apiRef.current.setPage(Math.max(0, pageCount - 1)); @@ -251,9 +264,51 @@ export const useGridPaginationModel = ( [apiRef], ); + const handleSortModelChange = React.useCallback(() => { + apiRef.current.setPage(0); + }, [apiRef]); + + /** + * Resets the page only if the active items or quick filter has changed from the last time. + * This is to avoid resetting the page when the filter model is changed + * because of and update of the operator from an item that does not have the value + * or reseting when the filter panel is just opened + */ + const handleFilterModelChange = React.useCallback>( + (filterModel) => { + const paginationModel = gridPaginationModelSelector(apiRef); + const currentActiveFilters = { + ...filterModel, + // replace items with the active items + items: gridFilterActiveItemsSelector(apiRef), + }; + + if (isDeepEqual(currentActiveFilters, previousFilterModel.current)) { + return; + } + + previousFilterModel.current = currentActiveFilters; + + if (paginationModel.page !== 0) { + apiRef.current.setPage(0); + } + }, + [apiRef], + ); + useGridApiEventHandler(apiRef, 'viewportInnerSizeChange', handleUpdateAutoPageSize); useGridApiEventHandler(apiRef, 'paginationModelChange', handlePaginationModelChange); useGridApiEventHandler(apiRef, 'rowCountChange', handleRowCountChange); + useGridApiEventHandler( + apiRef, + 'sortModelChange', + runIf(props.resetPageOnSortFilter, handleSortModelChange), + ); + useGridApiEventHandler( + apiRef, + 'filterModelChange', + runIf(props.resetPageOnSortFilter, handleFilterModelChange), + ); /** * EFFECTS diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index a15b89587f3dc..5672529fa952c 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -286,6 +286,12 @@ export interface DataGridPropsWithDefaultValues - Pagination', () => { const { render } = createRenderer(); + let apiRef: RefObject; function BaselineTestCase(props: Omit & { height?: number }) { const { height = 300, ...other } = props; + apiRef = useGridApiRef(); const basicData = useBasicDemoData(20, 2); return (
- +
); } @@ -258,18 +267,12 @@ describe(' - Pagination', () => { }); it('should throw if pageSize exceeds 100', () => { - let apiRef: RefObject; - function TestCase() { - apiRef = useGridApiRef(); - return ( - - ); - } - render(); + render( + , + ); expect(() => apiRef.current?.setPageSize(101)).to.throw( /`pageSize` cannot exceed 100 in the MIT version of the DataGrid./, ); @@ -615,6 +618,70 @@ describe(' - Pagination', () => { }); }); + describe('resetPageOnSortFilter prop', () => { + it('should reset page to 0 if sort or filter is applied and `resetPageOnSortFilter` is `true`', () => { + const { setProps } = render( + , + ); + + act(() => { + apiRef.current?.setPage(1); + }); + expect(apiRef.current!.state.pagination.paginationModel.page).to.equal(1); + + act(() => { + apiRef.current?.sortColumn('id', 'desc'); + apiRef.current?.setFilterModel({ + items: [ + { + field: 'id', + value: '1', + operator: '>=', + }, + ], + }); + }); + + // page stays the same after sorting and filtering + expect(apiRef.current!.state.pagination.paginationModel.page).to.equal(1); + + // enable reset + setProps({ + resetPageOnSortFilter: true, + }); + + act(() => { + apiRef.current?.sortColumn('id', 'asc'); + }); + // page is reset to 0 after sorting + expect(apiRef.current!.state.pagination.paginationModel.page).to.equal(0); + + // move to the next page again + act(() => { + apiRef.current?.setPage(1); + }); + expect(apiRef.current!.state.pagination.paginationModel.page).to.equal(1); + + act(() => { + apiRef.current?.setFilterModel({ + items: [ + { + field: 'id', + value: '1', + operator: '>=', + }, + ], + }); + }); + + // page is reset to 0 after filtering + expect(apiRef.current!.state.pagination.paginationModel.page).to.equal(0); + }); + }); + it('should make the first cell focusable after changing the page', () => { render(