diff --git a/docs/List.md b/docs/List.md
index 27ef41ac41e..c7ec0080fa3 100644
--- a/docs/List.md
+++ b/docs/List.md
@@ -814,6 +814,7 @@ export const PostList = (props) => (
* "edit" to redirect to the edition vue
* "show" to redirect to the show vue
* "expand" to open the `expand` panel
+* "toggleSelection" to trigger the `onToggleItem` function
* a function `(id, basePath, record) => path` to redirect to a custom path
**Tip**: If you pass a function, it can return `edit`, `show` or a router path. This allows to redirect to either `edit` or `show` after checking a condition on the record. For example:
diff --git a/packages/ra-ui-materialui/src/list/DatagridRow.js b/packages/ra-ui-materialui/src/list/DatagridRow.js
index d3f15fdba87..810f4c14f31 100644
--- a/packages/ra-ui-materialui/src/list/DatagridRow.js
+++ b/packages/ra-ui-materialui/src/list/DatagridRow.js
@@ -31,7 +31,7 @@ const sanitizeRestProps = ({
...rest
}) => rest;
-class DatagridRow extends Component {
+export class DatagridRow extends Component {
constructor(props) {
super(props);
this.state = {
@@ -62,33 +62,34 @@ class DatagridRow extends Component {
if (!rowClick) return;
- if (typeof rowClick === 'function') {
- const path = await rowClick(id, basePath, record);
- this.handleRedirection(path, event);
- return;
- }
+ const path =
+ typeof rowClick === 'function'
+ ? await rowClick(id, basePath, record)
+ : rowClick;
- this.handleRedirection(rowClick, event);
+ this.handleRedirection(path, event);
};
handleRedirection = (path, event) => {
const { basePath, id, push } = this.props;
- if (path === 'edit') {
- push(linkToRecord(basePath, id));
- return;
- }
- if (path === 'show') {
- push(linkToRecord(basePath, id, 'show'));
- return;
+ switch (path) {
+ case 'edit':
+ push(linkToRecord(basePath, id));
+ return;
+ case 'show':
+ push(linkToRecord(basePath, id, 'show'));
+ return;
+ case 'expand':
+ this.handleToggleExpanded(event);
+ return;
+ case 'toggleSelection':
+ this.handleToggle(event);
+ return;
+ default:
+ if (path) push(path);
+ return;
}
- if (path === 'expand') {
- this.handleToggleExpanded(event);
- return;
- }
- if (!path) return;
-
- push(path);
};
computeColSpan = props => {
diff --git a/packages/ra-ui-materialui/src/list/DatagridRow.spec.js b/packages/ra-ui-materialui/src/list/DatagridRow.spec.js
new file mode 100644
index 00000000000..b4fd923037b
--- /dev/null
+++ b/packages/ra-ui-materialui/src/list/DatagridRow.spec.js
@@ -0,0 +1,108 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { linkToRecord } from 'ra-core';
+
+import { DatagridRow } from './DatagridRow';
+
+describe('', () => {
+ const defaultProps = {
+ id: 15,
+ basePath: '/blob',
+ };
+
+ const event = { preventDefault: () => { }, stopPropagation: () => { } };
+
+ describe('rowClick', () => {
+ it("should redirect to edit page if the 'edit' option is selected", () => {
+ const push = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleClick(event);
+ expect(push.mock.calls).toEqual([
+ [linkToRecord(defaultProps.basePath, defaultProps.id)],
+ ]);
+ });
+
+ it("should redirect to show page if the 'show' option is selected", () => {
+ const push = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleClick(event);
+ expect(push.mock.calls).toEqual([
+ [linkToRecord(defaultProps.basePath, defaultProps.id, 'show')],
+ ]);
+ });
+
+ it("should change the expand state if the 'expand' option is selected", () => {
+ const wrapper = shallow(
+
+ );
+ expect(wrapper.state('expanded')).toBeFalsy();
+
+ wrapper.instance().handleClick(event);
+ expect(wrapper.state('expanded')).toBeTruthy();
+
+ wrapper.instance().handleClick(event);
+ expect(wrapper.state('expanded')).toBeFalsy();
+ });
+
+ it("should execute the onToggleItem function if the 'toggleSelection' option is selected", () => {
+ const onToggleItem = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleClick(event);
+
+ expect(onToggleItem.mock.calls.length).toEqual(1);
+ });
+
+ it('should redirect to the custom path if onRowClick is a string', () => {
+ const path = '/foo/bar';
+ const push = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleClick(event);
+ expect(push.mock.calls).toEqual([[path]]);
+ });
+
+ it('should evaluate the function and redirect to the result of that function if onRowClick is a custom function', async () => {
+ const push = jest.fn();
+ const customRowClick = () => '/bar/foo';
+ const wrapper = shallow(
+
+ );
+
+ await wrapper.instance().handleClick(event);
+ expect(push.mock.calls).toEqual([['/bar/foo']]);
+ });
+
+ it('should not call push if onRowClick is falsy', () => {
+ const push = jest.fn();
+ const wrapper = shallow(
+
+ );
+
+ wrapper.instance().handleClick(event);
+ expect(push.mock.calls.length).toEqual(0);
+ })
+ });
+});