Skip to content

Commit e2adb7d

Browse files
committed
✨(react) make optional DataGrid row selection
When using the selection feature on another project we realized that we needed to make some row non selectable at all by hiding the checkbox completely.
1 parent 418fac1 commit e2adb7d

5 files changed

Lines changed: 128 additions & 10 deletions

File tree

.changeset/wise-coins-tan.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@openfun/cunningham-react": minor
3+
---
4+
5+
make optional DataGrid row selection

packages/react/src/components/DataGrid/SimpleDataGrid.spec.tsx

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, screen, waitFor } from "@testing-library/react";
1+
import { queryByRole, render, screen, waitFor } from "@testing-library/react";
22
import React, { useState } from "react";
33
import { faker } from "@faker-js/faker";
44
import { getAllByRole, getByRole, within } from "@testing-library/dom";
@@ -267,6 +267,69 @@ describe("<SimpleDataGrid/>", () => {
267267
expect(lastRowSelection[rowsToSelect[1].id]).toBe(true);
268268
});
269269
});
270+
it.only("should not render selection checkboxes for unselectable rows", async () => {
271+
const rows = Array.from(Array(2))
272+
.map(() => ({
273+
id: faker.string.uuid(),
274+
firstName: faker.person.firstName(),
275+
lastName: faker.person.lastName(),
276+
email: faker.internet.email(),
277+
address: faker.location.streetAddress(),
278+
}))
279+
.sort((a, b) => a.firstName.localeCompare(b.firstName));
280+
rows[0].email = "admin@example.com";
281+
282+
const Wrapper = () => {
283+
const [rowSelection, setRowSelection] = useState({});
284+
lastRowSelection = rowSelection;
285+
return (
286+
<CunninghamProvider>
287+
<SimpleDataGrid
288+
columns={[
289+
{
290+
field: "firstName",
291+
headerName: "First name",
292+
},
293+
{
294+
field: "lastName",
295+
headerName: "Last name",
296+
},
297+
{
298+
field: "email",
299+
headerName: "Email",
300+
},
301+
{
302+
field: "address",
303+
headerName: "Address",
304+
},
305+
]}
306+
rows={rows}
307+
defaultSortModel={[
308+
{
309+
field: "firstName",
310+
sort: "asc",
311+
},
312+
]}
313+
enableRowSelection={(row) =>
314+
row.original.email !== "admin@example.com"
315+
}
316+
rowSelection={rowSelection}
317+
onRowSelectionChange={setRowSelection}
318+
/>
319+
</CunninghamProvider>
320+
);
321+
};
322+
323+
render(<Wrapper />);
324+
325+
// Check first row.
326+
let element = screen.getByTestId(rows[0].id);
327+
expect(queryByRole(element, "checkbox")).not.toBeInTheDocument();
328+
329+
// Check second row.
330+
element = screen.getByTestId(rows[1].id);
331+
expect(getByRole(element, "checkbox")).toBeInTheDocument();
332+
});
270333
it("should render a grid with working sortable columns", async () => {
271334
const rows = Array.from(Array(23))
272335
.map(() => ({

packages/react/src/components/DataGrid/index.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ below the table.
7070

7171
<Canvas sourceState="shown" of={Stories.ClientSideWithPagination}/>
7272

73+
You can also make a row non selectable by setting using `enableRowSelection` as a callback function that returns a boolean based on a condition.
74+
75+
<Canvas sourceState="shown" of={Stories.RowSelectionOptional}/>
76+
7377
As you can see, with `SimpleDataGrid` you can easily add pagination, sorting without have to worry about controlling
7478
their states.
7579

packages/react/src/components/DataGrid/index.stories.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,47 @@ export const ClientSideWithPagination = () => {
167167
);
168168
};
169169

170+
export const RowSelectionOptional = () => {
171+
const [rowSelection, setRowSelection] = useState({});
172+
173+
return (
174+
<>
175+
<SimpleDataGrid
176+
columns={[
177+
{
178+
field: "carName",
179+
headerName: "Car name",
180+
enableSorting: false,
181+
},
182+
{
183+
field: "year",
184+
headerName: "Year",
185+
},
186+
{
187+
field: "price",
188+
headerName: "Price ($)",
189+
highlight: true,
190+
},
191+
]}
192+
rows={databaseCars}
193+
defaultPaginationParams={{
194+
pageSize: 5,
195+
}}
196+
defaultSortModel={[
197+
{
198+
field: "price",
199+
sort: "desc",
200+
},
201+
]}
202+
enableRowSelection={(row) => row.original.year < 2024}
203+
rowSelection={rowSelection}
204+
onRowSelectionChange={setRowSelection}
205+
/>
206+
<div>Selected rows: {Object.keys(rowSelection).join(", ")}</div>
207+
</>
208+
);
209+
};
210+
170211
export const FullServerSide = () => {
171212
const database = useMemo(() => [...databaseUsersServer], []);
172213
const [rowSelection, setRowSelection] = useState({});

packages/react/src/components/DataGrid/utils.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,20 @@ export const useHeadlessColumns = <T extends Row>({
5252
id: HEADER_ID_SELECT,
5353
size: 34,
5454
header: () => null,
55-
cell: ({ row }) => (
56-
<Checkbox
57-
checked={row.getIsSelected()}
58-
disabled={!row.getCanSelect}
59-
indeterminate={row.getIsSomeSelected()}
60-
onChange={row.getToggleSelectedHandler()}
61-
aria-label={t("components.datagrid.row_selection_aria")}
62-
/>
63-
),
55+
cell: ({ row }) => {
56+
if (!row.getCanSelect()) {
57+
return null;
58+
}
59+
return (
60+
<Checkbox
61+
checked={row.getIsSelected()}
62+
disabled={!row.getCanSelect}
63+
indeterminate={row.getIsSomeSelected()}
64+
onChange={row.getToggleSelectedHandler()}
65+
aria-label={t("components.datagrid.row_selection_aria")}
66+
/>
67+
);
68+
},
6469
}),
6570
...headlessColumns,
6671
];

0 commit comments

Comments
 (0)