🐛(react) fix datagrid column unique key

If we had more than 1 columns with custom cells, we would get a warning
about duplicate keys, because every columns got the key `actions`.
We add the column index to the key to make it unique.
This commit is contained in:
Anthony LC
2023-07-10 16:06:18 +02:00
committed by NathanVss
parent 2344cdbe6f
commit e4c1df5b0b
4 changed files with 44 additions and 9 deletions

View File

@@ -0,0 +1,5 @@
---
"@openfun/cunningham-react": minor
---
fix datagrid column unique key

View File

@@ -235,6 +235,17 @@ describe("<DataGrid/>", () => {
highlight: true, highlight: true,
}, },
{ {
id: "firstName2",
field: "firstName",
headerName: "First name",
},
{
id: "lastName",
headerName: "Last Name",
renderCell: ({ row: { lastName } }) => lastName,
},
{
id: "buttonValidator",
renderCell: () => ( renderCell: () => (
<Button <Button
color="tertiary" color="tertiary"
@@ -250,17 +261,23 @@ describe("<DataGrid/>", () => {
); );
}; };
const error = vi.spyOn(console, "error").mockImplementation(() => {});
render(<Component />); render(<Component />);
database.forEach((row) => { database.forEach((row) => {
const element = screen.getByTestId(row.id); const element = screen.getByTestId(row.id);
const tds = getAllByRole(element, "cell"); const tds = getAllByRole(element, "cell");
expect(tds.length).toBe(2); expect(tds.length).toBe(4);
expect(tds[0].textContent).toEqual(row.firstName); expect(tds[0].textContent).toEqual(row.firstName);
getByRole(tds[1], "button", { expect(tds[1].textContent).toEqual(row.firstName);
expect(tds[2].textContent).toEqual(row.lastName);
getByRole(tds[3], "button", {
name: "delete", name: "delete",
}); });
}); });
expect(error).not.toHaveBeenCalled();
}); });
it("should render highlighted column", async () => { it("should render highlighted column", async () => {

View File

@@ -23,13 +23,25 @@ export interface Row extends Record<string, any> {
id: string; id: string;
} }
export interface Column<T extends Row = Row> { export interface ColumnField {
field?: string; id?: string;
field: string;
renderCell?: never;
}
export interface ColumnCustomCell<T extends Row = Row> {
id: string;
renderCell: (params: { row: T }) => React.ReactNode;
}
export type Column<T extends Row = Row> = (
| ColumnCustomCell<T>
| ColumnField
) & {
headerName?: string; headerName?: string;
highlight?: boolean; highlight?: boolean;
renderCell?: (params: { row: T }) => React.ReactNode;
enableSorting?: boolean; enableSorting?: boolean;
} };
export type SortModel = { field: string; sort: "asc" | "desc" | null }[]; export type SortModel = { field: string; sort: "asc" | "desc" | null }[];

View File

@@ -24,19 +24,20 @@ export const useHeadlessColumns = <T extends Row>({
const columnHelper = createColumnHelper<T>(); const columnHelper = createColumnHelper<T>();
let headlessColumns = columns.map((column) => { let headlessColumns = columns.map((column) => {
const opts = { const opts = {
id: column.field ?? "actions", id: column.renderCell ? column.id : column.id ?? column.field,
enableSorting: column.enableSorting, enableSorting: column.enableSorting,
header: column.headerName, header: column.headerName,
}; };
if (column.field) { if (!column.renderCell) {
// The any cast is needed because the type of the accessor is hard-defined on react-table. // The any cast is needed because the type of the accessor is hard-defined on react-table.
// On our side we only use string as type for simplicity purpose. // On our side we only use string as type for simplicity purpose.
return columnHelper.accessor(column.field as any, opts); return columnHelper.accessor(column.field as any, opts);
} }
return columnHelper.display({ return columnHelper.display({
...opts, ...opts,
cell: (info) => { cell: (info) => {
return column.renderCell!({ row: info.row.original }); return column.renderCell({ row: info.row.original });
}, },
}); });
}); });