Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Fix checkboxSelectionVisibleOnly reset the selection on filtering #14677

Merged
merged 10 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,43 @@ describe('<DataGridPro /> - Row selection', () => {
fireEvent.click(selectAllCheckbox);
expect(apiRef.current.getSelectedRows()).to.have.length(2);
});

// https://github.com/mui/mui-x/issues/14074
it('should select all the rows of the current page keeping the previously selected rows when a filter is applied', () => {
render(
<TestDataGridSelection
rowLength={50}
checkboxSelection
checkboxSelectionVisibleOnly
initialState={{
pagination: { paginationModel: { pageSize: 2 } },
filter: {
filterModel: {
items: [
{
field: 'currencyPair',
value: 'usd',
operator: 'contains',
},
],
},
},
}}
pagination
pageSizeOptions={[2]}
/>,
);

fireEvent.click(getCell(0, 0).querySelector('input')!);
expect(apiRef.current.getSelectedRows()).to.have.keys([0]);
fireEvent.click(screen.getByRole('button', { name: /next page/i }));
const selectAllCheckbox: HTMLInputElement = screen.getByRole('checkbox', {
name: /select all rows/i,
});
fireEvent.click(selectAllCheckbox);
expect(apiRef.current.getSelectedRows()).to.have.keys([0, 3, 4]);
expect(selectAllCheckbox.checked).to.equal(true);
});
});

describe('apiRef: getSelectedRows', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { GridRowId } from '../../../models/gridRows';
import { GridSignature, useGridApiEventHandler } from '../../utils/useGridApiEventHandler';
import { useGridApiMethod } from '../../utils/useGridApiMethod';
import { useGridLogger } from '../../utils/useGridLogger';
import { gridRowsLookupSelector } from '../rows/gridRowsSelector';
import {
gridRowSelectionStateSelector,
selectedGridRowsSelector,
Expand All @@ -20,7 +19,7 @@ import { gridPaginatedVisibleSortedGridRowIdsSelector } from '../pagination';
import { gridFocusCellSelector } from '../focus/gridFocusStateSelector';
import {
gridExpandedSortedRowIdsSelector,
gridFilterModelSelector,
gridFilteredRowsLookupSelector,
} from '../filter/gridFilterSelector';
import { GRID_CHECKBOX_SELECTION_COL_DEF, GRID_ACTIONS_COLUMN_TYPE } from '../../../colDef';
import { GridCellModes } from '../../../models/gridEditRowModel';
Expand Down Expand Up @@ -331,14 +330,14 @@ export const useGridRowSelection = (
return;
}
const currentSelection = gridRowSelectionStateSelector(apiRef.current.state);
const rowsLookup = gridRowsLookupSelector(apiRef);
const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);

// We clone the existing object to avoid mutating the same object returned by the selector to others part of the project
const selectionLookup = { ...selectedIdsLookupSelector(apiRef) };

let hasChanged = false;
currentSelection.forEach((id: GridRowId) => {
if (!rowsLookup[id]) {
if (!filteredRowsLookup[id]) {
delete selectionLookup[id];
hasChanged = true;
}
Expand Down Expand Up @@ -452,8 +451,7 @@ export const useGridRowSelection = (
? gridPaginatedVisibleSortedGridRowIdsSelector(apiRef)
: gridExpandedSortedRowIdsSelector(apiRef);

const filterModel = gridFilterModelSelector(apiRef);
apiRef.current.selectRows(rowsToBeSelected, params.value, filterModel?.items.length > 0);
apiRef.current.selectRows(rowsToBeSelected, params.value);
},
[apiRef, props.checkboxSelectionVisibleOnly, props.pagination, props.paginationMode],
);
Expand Down Expand Up @@ -539,6 +537,11 @@ export const useGridRowSelection = (
'sortedRowsSet',
runIfRowSelectionIsEnabled(removeOutdatedSelection),
);
useGridApiEventHandler(
apiRef,
'filteredRowsSet',
runIfRowSelectionIsEnabled(removeOutdatedSelection),
);
useGridApiEventHandler(apiRef, 'rowClick', runIfRowSelectionIsEnabled(handleRowClick));
useGridApiEventHandler(
apiRef,
Expand Down
36 changes: 34 additions & 2 deletions packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,38 @@ describe('<DataGrid /> - Row selection', () => {
expect(input2.checked).to.equal(true);
});

it('should remove the selection from rows that are filtered out', async function test() {
if (isJSDOM) {
this.skip();
}
render(
<TestDataGridSelection
checkboxSelection
initialState={{
preferencePanel: {
open: true,
openedPanelValue: GridPreferencePanelsValue.filters,
},
}}
/>,
);
const selectAllCheckbox = screen.getByRole('checkbox', { name: 'Select all rows' });
fireEvent.click(selectAllCheckbox);
await act(() => {
expect(getSelectedRowIds()).to.deep.equal([0, 1, 2, 3]);
});
expect(grid('selectedRowCount')?.textContent).to.equal('4 rows selected');

fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), {
target: { value: 1 },
});
await waitFor(() => {
// Previous selection is cleaned with only the filtered rows
expect(getSelectedRowIds()).to.deep.equal([1]);
});
expect(grid('selectedRowCount')?.textContent).to.equal('1 row selected');
});

it('should only select filtered items when "select all" is toggled after applying a filter', async () => {
render(
<TestDataGridSelection
Expand All @@ -390,10 +422,10 @@ describe('<DataGrid /> - Row selection', () => {
target: { value: 1 },
});
await waitFor(() => {
// Previous selection remains, but only one row is visible
// Previous selection is cleared and only the filtered row is selected
expect(getSelectedRowIds()).to.deep.equal([1]);
});
expect(grid('selectedRowCount')?.textContent).to.equal('4 rows selected');
expect(grid('selectedRowCount')?.textContent).to.equal('1 row selected');

fireEvent.click(selectAllCheckbox); // Unselect all
await waitFor(() => {
Expand Down