Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/wise-coins-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@openfun/cunningham-react": minor
---

make optional DataGrid row selection
65 changes: 64 additions & 1 deletion packages/react/src/components/DataGrid/SimpleDataGrid.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render, screen, waitFor } from "@testing-library/react";
import { queryByRole, render, screen, waitFor } from "@testing-library/react";
import React, { useState } from "react";
import { faker } from "@faker-js/faker";
import { getAllByRole, getByRole, within } from "@testing-library/dom";
Expand Down Expand Up @@ -267,6 +267,69 @@ describe("<SimpleDataGrid/>", () => {
expect(lastRowSelection[rowsToSelect[1].id]).toBe(true);
});
});
it("should not render selection checkboxes for unselectable rows", async () => {
const rows = Array.from(Array(2))
.map(() => ({
id: faker.string.uuid(),
firstName: faker.person.firstName(),
lastName: faker.person.lastName(),
email: faker.internet.email(),
address: faker.location.streetAddress(),
}))
.sort((a, b) => a.firstName.localeCompare(b.firstName));
rows[0].email = "[email protected]";

const Wrapper = () => {
const [rowSelection, setRowSelection] = useState({});

return (
<CunninghamProvider>
<SimpleDataGrid
columns={[
{
field: "firstName",
headerName: "First name",
},
{
field: "lastName",
headerName: "Last name",
},
{
field: "email",
headerName: "Email",
},
{
field: "address",
headerName: "Address",
},
]}
rows={rows}
defaultSortModel={[
{
field: "firstName",
sort: "asc",
},
]}
enableRowSelection={(row) =>
row.original.email !== "[email protected]"
}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}
/>
</CunninghamProvider>
);
};

render(<Wrapper />);

// Check first row.
let element = screen.getByTestId(rows[0].id);
expect(queryByRole(element, "checkbox")).not.toBeInTheDocument();

// Check second row.
element = screen.getByTestId(rows[1].id);
expect(getByRole(element, "checkbox")).toBeInTheDocument();
});
it("should render a grid with working sortable columns", async () => {
const rows = Array.from(Array(23))
.map(() => ({
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/components/DataGrid/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ below the table.

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

You can also make a row non selectable by setting using `enableRowSelection` as a callback function that returns a boolean based on a condition.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You can also make a row non selectable by setting using `enableRowSelection` as a callback function that returns a boolean based on a condition.
You can also make a row non selectable by setting `enableRowSelection` prop with a callback function that returns a boolean based on a condition.


<Canvas sourceState="shown" of={Stories.RowSelectionOptional}/>

As you can see, with `SimpleDataGrid` you can easily add pagination, sorting without have to worry about controlling
their states.

Expand Down
41 changes: 41 additions & 0 deletions packages/react/src/components/DataGrid/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,47 @@ export const ClientSideWithPagination = () => {
);
};

export const RowSelectionOptional = () => {
const [rowSelection, setRowSelection] = useState({});

return (
<>
<SimpleDataGrid
columns={[
{
field: "carName",
headerName: "Car name",
enableSorting: false,
},
{
field: "year",
headerName: "Year",
},
{
field: "price",
headerName: "Price ($)",
highlight: true,
},
]}
rows={databaseCars}
defaultPaginationParams={{
pageSize: 5,
}}
defaultSortModel={[
{
field: "price",
sort: "desc",
},
]}
enableRowSelection={(row) => row.original.year < 2024}
rowSelection={rowSelection}
onRowSelectionChange={setRowSelection}
/>
<div>Selected rows: {Object.keys(rowSelection).join(", ")}</div>
</>
);
};

export const FullServerSide = () => {
const database = useMemo(() => [...databaseUsersServer], []);
const [rowSelection, setRowSelection] = useState({});
Expand Down
23 changes: 14 additions & 9 deletions packages/react/src/components/DataGrid/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,20 @@ export const useHeadlessColumns = <T extends Row>({
id: HEADER_ID_SELECT,
size: 34,
header: () => null,
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect}
indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
aria-label={t("components.datagrid.row_selection_aria")}
/>
),
cell: ({ row }) => {
if (!row.getCanSelect()) {
return null;
}
return (
<Checkbox
checked={row.getIsSelected()}
disabled={!row.getCanSelect}
Copy link
Collaborator

@jbpenrath jbpenrath Aug 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your change highlights this logic is wrong

Suggested change
disabled={!row.getCanSelect}
disabled={!row.getCanSelect()}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right on this, but we need a way to hide checkboxes, not just grey them out. WDYT about adding a props on DataGrid named hideSelectCellWhenDisabled ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(ping) :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops! I did not our reply ...
Ok let's do that

indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
aria-label={t("components.datagrid.row_selection_aria")}
/>
);
},
}),
...headlessColumns,
];
Expand Down