diff --git a/.changeset/selfish-phones-enjoy.md b/.changeset/selfish-phones-enjoy.md
new file mode 100644
index 0000000..ca9e447
--- /dev/null
+++ b/.changeset/selfish-phones-enjoy.md
@@ -0,0 +1,5 @@
+---
+"@openfun/cunningham-react": minor
+---
+
+fix datagrid column unique key
diff --git a/packages/react/src/components/DataGrid/index.spec.tsx b/packages/react/src/components/DataGrid/index.spec.tsx
index 1928629..4d56601 100644
--- a/packages/react/src/components/DataGrid/index.spec.tsx
+++ b/packages/react/src/components/DataGrid/index.spec.tsx
@@ -235,6 +235,17 @@ describe("", () => {
highlight: true,
},
{
+ id: "firstName2",
+ field: "firstName",
+ headerName: "First name",
+ },
+ {
+ id: "lastName",
+ headerName: "Last Name",
+ renderCell: ({ row: { lastName } }) => lastName,
+ },
+ {
+ id: "buttonValidator",
renderCell: () => (
", () => {
);
};
+ const error = vi.spyOn(console, "error").mockImplementation(() => {});
+
render();
database.forEach((row) => {
const element = screen.getByTestId(row.id);
const tds = getAllByRole(element, "cell");
- expect(tds.length).toBe(2);
+ expect(tds.length).toBe(4);
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",
});
});
+
+ expect(error).not.toHaveBeenCalled();
});
it("should render highlighted column", async () => {
diff --git a/packages/react/src/components/DataGrid/index.tsx b/packages/react/src/components/DataGrid/index.tsx
index a2bbd57..a6a427c 100644
--- a/packages/react/src/components/DataGrid/index.tsx
+++ b/packages/react/src/components/DataGrid/index.tsx
@@ -23,13 +23,25 @@ export interface Row extends Record {
id: string;
}
-export interface Column {
- field?: string;
+export interface ColumnField {
+ id?: string;
+ field: string;
+ renderCell?: never;
+}
+
+export interface ColumnCustomCell {
+ id: string;
+ renderCell: (params: { row: T }) => React.ReactNode;
+}
+
+export type Column = (
+ | ColumnCustomCell
+ | ColumnField
+) & {
headerName?: string;
highlight?: boolean;
- renderCell?: (params: { row: T }) => React.ReactNode;
enableSorting?: boolean;
-}
+};
export type SortModel = { field: string; sort: "asc" | "desc" | null }[];
diff --git a/packages/react/src/components/DataGrid/utils.tsx b/packages/react/src/components/DataGrid/utils.tsx
index 6cf051e..0827e26 100644
--- a/packages/react/src/components/DataGrid/utils.tsx
+++ b/packages/react/src/components/DataGrid/utils.tsx
@@ -24,19 +24,20 @@ export const useHeadlessColumns = ({
const columnHelper = createColumnHelper();
let headlessColumns = columns.map((column) => {
const opts = {
- id: column.field ?? "actions",
+ id: column.renderCell ? column.id : column.id ?? column.field,
enableSorting: column.enableSorting,
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.
// On our side we only use string as type for simplicity purpose.
return columnHelper.accessor(column.field as any, opts);
}
+
return columnHelper.display({
...opts,
cell: (info) => {
- return column.renderCell!({ row: info.row.original });
+ return column.renderCell({ row: info.row.original });
},
});
});