diff --git a/packages/ra-ui-materialui/src/list/datagrid/Datagrid.spec.tsx b/packages/ra-ui-materialui/src/list/datagrid/Datagrid.spec.tsx index b3f15cedba6..632203cb80e 100644 --- a/packages/ra-ui-materialui/src/list/datagrid/Datagrid.spec.tsx +++ b/packages/ra-ui-materialui/src/list/datagrid/Datagrid.spec.tsx @@ -10,7 +10,7 @@ import { import { ThemeProvider, createTheme } from '@mui/material'; import { Datagrid } from './Datagrid'; -import { AccessControl, SelectAllButton } from './Datagrid.stories'; +import { AccessControl, FullApp, SelectAllButton } from './Datagrid.stories'; const TitleField = () => { const record = useRecordContext(); @@ -126,6 +126,36 @@ describe('', () => { expect(screen.queryByText('Select All')).toBeNull(); }); + describe('row selection', () => { + it('should reveal bulk delete button by default on row selection', async () => { + render(); + const checkboxes = await screen.findAllByRole('checkbox'); + fireEvent.click(checkboxes[1]); + await screen.findByLabelText('Delete'); + await screen.findByText('1 item selected'); + fireEvent.click(checkboxes[2]); + await screen.findByText('2 items selected'); + }); + it('should reveal select all button when selecting the entire page', async () => { + render(); + const checkboxes = await screen.findAllByRole('checkbox'); + fireEvent.click(checkboxes[0]); + const selectAllButton = await screen.findByText('Select all'); + selectAllButton.click(); + await screen.findByText('7 items selected'); + }); + it('should only unselect the current page records', async () => { + render(); + const checkboxes = await screen.findAllByRole('checkbox'); + fireEvent.click(checkboxes[0]); + const selectAllButton = await screen.findByText('Select all'); + selectAllButton.click(); + await screen.findByText('7 items selected'); + fireEvent.click(checkboxes[0]); + await screen.findByText('2 items selected'); + }); + }); + describe('selecting items with the shift key', () => { it('should call onSelect with the correct ids when the last selection is after the first', () => { const Test = ({ selectedIds = [] }) => ( diff --git a/packages/ra-ui-materialui/src/list/datagrid/Datagrid.stories.tsx b/packages/ra-ui-materialui/src/list/datagrid/Datagrid.stories.tsx index 07e791d16e1..7f77ef9ee09 100644 --- a/packages/ra-ui-materialui/src/list/datagrid/Datagrid.stories.tsx +++ b/packages/ra-ui-materialui/src/list/datagrid/Datagrid.stories.tsx @@ -10,6 +10,7 @@ import { TestMemoryRouter, SortPayload, AuthProvider, + memoryStore, } from 'ra-core'; import fakeRestDataProvider from 'ra-data-fakerest'; import defaultMessages from 'ra-language-english'; @@ -558,18 +559,21 @@ export const RowClickFalse = () => ( export const FullApp = ({ rowClick, + perPage = undefined, }: { rowClick?: DatagridRowProps['rowClick']; + perPage?: number; }) => ( defaultMessages, 'en')} + store={memoryStore()} > ( - + } rowClick={rowClick} diff --git a/packages/ra-ui-materialui/src/list/datagrid/DatagridHeader.tsx b/packages/ra-ui-materialui/src/list/datagrid/DatagridHeader.tsx index 55c2186928a..6e4e44288af 100644 --- a/packages/ra-ui-materialui/src/list/datagrid/DatagridHeader.tsx +++ b/packages/ra-ui-materialui/src/list/datagrid/DatagridHeader.tsx @@ -58,17 +58,18 @@ export const DatagridHeader = (props: DatagridHeaderProps) => { event.target.checked ? selectedIds.concat( data - .filter( - record => !selectedIds.includes(record.id) - ) .filter(record => + !selectedIds.includes(record.id) && isRowSelectable ? isRowSelectable(record) : true ) .map(record => record.id) ) - : [] + : // We should only unselect the ids present in the current page + selectedIds.filter( + id => !data.some(record => record.id === id) + ) ); }, [data, onSelect, isRowSelectable, selectedIds] diff --git a/packages/ra-ui-materialui/src/list/datatable/DataTable.spec.tsx b/packages/ra-ui-materialui/src/list/datatable/DataTable.spec.tsx index 2eadc6c78b5..1b7d20aacb5 100644 --- a/packages/ra-ui-materialui/src/list/datatable/DataTable.spec.tsx +++ b/packages/ra-ui-materialui/src/list/datatable/DataTable.spec.tsx @@ -235,6 +235,16 @@ describe('DataTable', () => { selectAllButton.click(); await screen.findByText('7 items selected'); }); + it('should only unselect the current page records', async () => { + render(); + const checkboxes = await screen.findAllByRole('checkbox'); + fireEvent.click(checkboxes[0]); + const selectAllButton = await screen.findByText('Select all'); + selectAllButton.click(); + await screen.findByText('7 items selected'); + fireEvent.click(checkboxes[0]); + await screen.findByText('2 items selected'); + }); }); describe('isRowSelectable', () => { it('should allow to disable row selection', async () => { diff --git a/packages/ra-ui-materialui/src/list/datatable/SelectPageCheckbox.tsx b/packages/ra-ui-materialui/src/list/datatable/SelectPageCheckbox.tsx index c4c726bf859..48b67f2fe78 100644 --- a/packages/ra-ui-materialui/src/list/datatable/SelectPageCheckbox.tsx +++ b/packages/ra-ui-materialui/src/list/datatable/SelectPageCheckbox.tsx @@ -22,17 +22,18 @@ export const SelectPageCheckbox = () => { event.target.checked ? selectedIds.concat( data - .filter( - record => !selectedIds.includes(record.id) - ) .filter(record => + !selectedIds.includes(record.id) && isRowSelectable ? isRowSelectable(record) : true ) .map(record => record.id) ) - : [] + : // We should only unselect the ids present in the current page + selectedIds.filter( + id => !data.some(record => record.id === id) + ) ); }, [data, onSelect, isRowSelectable, selectedIds]