From 39fa577374918ee8fbee4ecdf737fef98fddf701 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 14 Dec 2021 09:19:24 +0100 Subject: [PATCH 01/33] [DataGridPro] Allow to group rows based on column value --- .../api-docs/data-grid/data-grid-pro.json | 12 + docs/pages/api-docs/data-grid/data-grid.json | 2 + docs/pages/api-docs/data-grid/grid-api.md | 182 +- docs/pages/api-docs/data-grid/grid-col-def.md | 2 + .../data-grid/grid-grouping-columns-api.json | 26 + .../api/buildInterfacesDocumentation.ts | 1 + .../data-grid/accessibility/accessibility.md | 27 +- .../components/data-grid/events/events.json | 6 + .../CustomGroupingColumnTreeData.js | 255 -- .../CustomGroupingColumnTreeData.tsx | 197 -- .../CustomGroupingColumnTreeData.tsx.preview | 7 - .../DefaultGroupingExpansionDepthTreeData.js | 121 - .../DefaultGroupingExpansionDepthTreeData.tsx | 121 - ...GroupingExpansionDepthTreeData.tsx.preview | 7 - .../group-pivot/GroupingColumnsApiNoSnap.js | 7 + .../GroupingColumnsColDefCanBeGrouped.js | 76 + .../GroupingColumnsColDefCanBeGrouped.tsx | 87 + ...upingColumnsColDefCanBeGrouped.tsx.preview | 14 + .../group-pivot/GroupingColumnsControlled.js | 68 + .../group-pivot/GroupingColumnsControlled.tsx | 78 + .../GroupingColumnsControlled.tsx.preview | 10 + ...pingColumnsCustomGroupingColDefCallback.js | 102 + ...ingColumnsCustomGroupingColDefCallback.tsx | 113 + ...oupingColumnsCustomGroupingColDefObject.js | 71 + ...upingColumnsCustomGroupingColDefObject.tsx | 82 + .../GroupingColumnsDefaultExpansionDepth.js | 69 + .../GroupingColumnsDefaultExpansionDepth.tsx | 80 + ...ngColumnsDefaultExpansionDepth.tsx.preview | 15 + .../group-pivot/GroupingColumnsDisabled.js | 20 + .../group-pivot/GroupingColumnsDisabled.tsx | 20 + .../GroupingColumnsDisabled.tsx.preview | 8 + .../group-pivot/GroupingColumnsFullExample.js | 80 + .../GroupingColumnsFullExample.tsx | 90 + .../GroupingColumnsHideDescendantCount.js | 71 + .../GroupingColumnsHideDescendantCount.tsx | 82 + .../GroupingColumnsInitialState.js | 68 + .../GroupingColumnsInitialState.tsx | 79 + .../GroupingColumnsInitialState.tsx.preview | 14 + .../group-pivot/GroupingColumnsKeyGetter.js | 81 + .../group-pivot/GroupingColumnsKeyGetter.tsx | 96 + .../GroupingColumnsKeyGetter.tsx.preview | 13 + .../GroupingColumnsKeyGetterValueGetter.js | 92 + .../GroupingColumnsKeyGetterValueGetter.tsx | 109 + ...ingColumnsKeyGetterValueGetter.tsx.preview | 13 + .../GroupingColumnsLeafWithValue.js | 69 + .../GroupingColumnsLeafWithValue.tsx | 80 + .../GroupingColumnsLeafWithValue.tsx.preview | 14 + .../GroupingColumnsMultipleGroupingCol.js | 68 + .../GroupingColumnsMultipleGroupingCol.tsx | 79 + ...pingColumnsMultipleGroupingCol.tsx.preview | 14 + .../GroupingColumnsRowsWithMissingGroups.js | 68 + .../GroupingColumnsRowsWithMissingGroups.tsx | 79 + ...ngColumnsRowsWithMissingGroups.tsx.preview | 14 + .../GroupingColumnsSetChildrenExpansion.js | 90 + .../GroupingColumnsSetChildrenExpansion.tsx | 97 + .../GroupingColumnsSingleGroupingCol.js | 68 + .../GroupingColumnsSingleGroupingCol.tsx | 79 + ...oupingColumnsSingleGroupingCol.tsx.preview | 14 + ...ingColumnsSortingMultipleGroupingColDef.js | 78 + ...ngColumnsSortingMultipleGroupingColDef.tsx | 89 + ...upingColumnsSortingSingleGroupingColDef.js | 105 + ...pingColumnsSortingSingleGroupingColDef.tsx | 116 + .../group-pivot/SetRowExpansionTreeData.js | 145 -- .../group-pivot/SetRowExpansionTreeData.tsx | 147 -- .../SetRowExpansionTreeData.tsx.preview | 11 - ...js => TreeDataDisableChildrenFiltering.js} | 2 +- ...x => TreeDataDisableChildrenFiltering.tsx} | 2 +- ...a.js => TreeDataDisableChildrenSorting.js} | 2 +- ...tsx => TreeDataDisableChildrenSorting.tsx} | 2 +- .../{BasicTreeData.js => TreeDataSimple.js} | 2 +- .../{BasicTreeData.tsx => TreeDataSimple.tsx} | 2 +- ...tsx.preview => TreeDataSimple.tsx.preview} | 0 .../data-grid/group-pivot/group-pivot.md | 201 +- .../components/data-grid/overview/overview.md | 3 +- .../api-docs/data-grid/data-grid-pro-pt.json | 13 +- .../api-docs/data-grid/data-grid-pro-zh.json | 13 +- .../api-docs/data-grid/data-grid-pro.json | 13 +- .../api-docs/data-grid/data-grid-pt.json | 4 +- .../api-docs/data-grid/data-grid-zh.json | 4 +- .../api-docs/data-grid/data-grid.json | 4 +- .../grid/_modules_/grid/GridComponentProps.ts | 23 +- .../grid/components/cell/GridBooleanCell.tsx | 14 +- .../cell/GridGroupingColumnLeafCell.tsx | 16 + .../cell/GridGroupingCriteriaCell.tsx | 164 ++ .../components/containers/GridRootStyles.ts | 10 + .../_modules_/grid/components/icons/index.tsx | 2 +- .../GridGroupingColumnsMenuItems.tsx | 116 + .../grid/constants/localeTextConstants.ts | 5 + packages/grid/_modules_/grid/gridClasses.ts | 2 + .../hooks/features/filter/gridFilterState.ts | 13 +- .../hooks/features/filter/useGridFilter.ts | 25 +- .../groupingColumns/createGroupingColDef.tsx | 360 +++ .../gridGroupingColumnsInterfaces.ts | 37 + .../gridGroupingColumnsSelector.ts | 17 + .../gridGroupingColumnsUtils.ts | 147 ++ .../hooks/features/groupingColumns/index.ts | 2 + .../useGridGroupingColumns.tsx | 483 ++++ .../_modules_/grid/hooks/features/index.ts | 1 + .../hooks/features/sorting/useGridSorting.ts | 1 + .../treeData/gridTreeDataGroupColDef.ts | 3 +- .../features/treeData/gridTreeDataUtils.ts | 3 +- .../grid/hooks/utils/useGridProcessedProps.ts | 4 + packages/grid/_modules_/grid/locales/arSD.ts | 5 + packages/grid/_modules_/grid/locales/bgBG.ts | 5 + packages/grid/_modules_/grid/locales/deDE.ts | 5 + packages/grid/_modules_/grid/locales/elGR.ts | 5 + packages/grid/_modules_/grid/locales/esES.ts | 5 + packages/grid/_modules_/grid/locales/faIR.ts | 5 + packages/grid/_modules_/grid/locales/frFR.ts | 5 + packages/grid/_modules_/grid/locales/heIL.ts | 5 + packages/grid/_modules_/grid/locales/itIT.ts | 5 + packages/grid/_modules_/grid/locales/jaJP.ts | 5 + packages/grid/_modules_/grid/locales/koKR.ts | 5 + packages/grid/_modules_/grid/locales/nlNL.ts | 5 + packages/grid/_modules_/grid/locales/plPL.ts | 5 + packages/grid/_modules_/grid/locales/ptBR.ts | 5 + packages/grid/_modules_/grid/locales/ruRU.ts | 5 + packages/grid/_modules_/grid/locales/skSK.ts | 5 + packages/grid/_modules_/grid/locales/trTR.ts | 5 + packages/grid/_modules_/grid/locales/ukUA.ts | 5 + packages/grid/_modules_/grid/locales/viVN.ts | 5 + packages/grid/_modules_/grid/locales/zhCN.ts | 5 + .../grid/_modules_/grid/models/api/gridApi.ts | 2 + .../grid/models/api/gridLocaleTextApi.ts | 5 + .../grid/models/colDef/gridColDef.ts | 34 +- .../grid/models/colDef/gridStringColDef.ts | 1 + .../grid/models/events/gridEventLookup.ts | 2 + .../grid/models/events/gridEvents.ts | 4 + .../grid/models/gridIconSlotsComponent.ts | 8 + .../_modules_/grid/models/gridOptions.tsx | 25 +- .../grid/_modules_/grid/models/gridRows.ts | 3 + .../_modules_/grid/models/gridSortModel.ts | 3 +- .../grid/_modules_/grid/models/gridState.ts | 9 + .../grid/models/params/gridCellParams.ts | 22 +- .../grid/utils/tree/buildRowTree.test.ts | 87 +- .../src/commodities.columns.tsx | 10 +- .../grid/x-data-grid-generator/src/index.ts | 1 + .../src/renderer/renderCountry.tsx | 4 + .../src/renderer/renderPnl.tsx | 4 + .../src/renderer/renderProgress.tsx | 4 + .../src/renderer/renderStatus.tsx | 6 +- .../src/renderer/renderTotalPrice.tsx | 3 + .../x-data-grid-generator/src/useMovieData.ts | 284 +++ .../grid/x-data-grid-pro/src/DataGridPro.tsx | 32 +- .../groupingColumns.DataGridPro.test.tsx | 2050 +++++++++++++++++ .../src/useDataGridProComponent.tsx | 2 + .../grid/x-data-grid/src/DataGridProps.ts | 6 + .../grid/x-data-grid/src/useDataGridProps.ts | 5 + scripts/exportsSnapshot.json | 8 + 149 files changed, 7555 insertions(+), 1182 deletions(-) create mode 100644 docs/pages/api-docs/data-grid/grid-grouping-columns-api.json delete mode 100644 docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.js delete mode 100644 docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx delete mode 100644 docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx.preview delete mode 100644 docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.js delete mode 100644 docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx delete mode 100644 docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx delete mode 100644 docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.js delete mode 100644 docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx delete mode 100644 docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx.preview rename docs/src/pages/components/data-grid/group-pivot/{DisableChildrenFilteringTreeData.js => TreeDataDisableChildrenFiltering.js} (98%) rename docs/src/pages/components/data-grid/group-pivot/{DisableChildrenFilteringTreeData.tsx => TreeDataDisableChildrenFiltering.tsx} (98%) rename docs/src/pages/components/data-grid/group-pivot/{DisableChildrenSortingTreeData.js => TreeDataDisableChildrenSorting.js} (98%) rename docs/src/pages/components/data-grid/group-pivot/{DisableChildrenSortingTreeData.tsx => TreeDataDisableChildrenSorting.tsx} (98%) rename docs/src/pages/components/data-grid/group-pivot/{BasicTreeData.js => TreeDataSimple.js} (98%) rename docs/src/pages/components/data-grid/group-pivot/{BasicTreeData.tsx => TreeDataSimple.tsx} (98%) rename docs/src/pages/components/data-grid/group-pivot/{BasicTreeData.tsx.preview => TreeDataSimple.tsx.preview} (100%) create mode 100644 packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx create mode 100644 packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx create mode 100644 packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts create mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx create mode 100644 packages/grid/x-data-grid-generator/src/useMovieData.ts create mode 100644 packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx diff --git a/docs/pages/api-docs/data-grid/data-grid-pro.json b/docs/pages/api-docs/data-grid/data-grid-pro.json index 3b5d4f525e72b..f565e14444d06 100644 --- a/docs/pages/api-docs/data-grid/data-grid-pro.json +++ b/docs/pages/api-docs/data-grid/data-grid-pro.json @@ -42,6 +42,7 @@ "disableColumnSelector": { "type": { "name": "bool" } }, "disableDensitySelector": { "type": { "name": "bool" } }, "disableExtendRowFullWidth": { "type": { "name": "bool" } }, + "disableGroupingColumns": { "type": { "name": "bool" } }, "disableMultipleColumnsFiltering": { "type": { "name": "bool" } }, "disableMultipleColumnsSorting": { "type": { "name": "bool" } }, "disableMultipleSelection": { "type": { "name": "bool" } }, @@ -53,6 +54,9 @@ }, "editRowsModel": { "type": { "name": "object" } }, "error": { "type": { "name": "any" } }, + "experimentalFeatures": { + "type": { "name": "shape", "description": "{ groupingColumns?: bool }" } + }, "filterMode": { "type": { "name": "custom", "description": "'client'
| 'server'" }, "default": "\"client\"" @@ -68,6 +72,11 @@ "getRowId": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, + "groupingColumnMode": { + "type": { "name": "enum", "description": "'multiple'
| 'single'" }, + "default": "'single'" + }, + "groupingColumnsModel": { "type": { "name": "arrayOf", "description": "Array<string>" } }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, @@ -121,6 +130,7 @@ "onEditRowsModelChange": { "type": { "name": "func" } }, "onError": { "type": { "name": "func" } }, "onFilterModelChange": { "type": { "name": "func" } }, + "onGroupingColumnsModelChange": { "type": { "name": "func" } }, "onPageChange": { "type": { "name": "func" } }, "onPageSizeChange": { "type": { "name": "func" } }, "onPinnedColumnsChange": { "type": { "name": "func" } }, @@ -224,6 +234,8 @@ "ExportIcon": { "default": "GridSaveAltIcon", "type": { "name": "elementType" } }, "FilterPanel": { "default": "GridFilterPanel", "type": { "name": "elementType" } }, "Footer": { "default": "GridFooter", "type": { "name": "elementType" } }, + "GroupingCriteriaCollapseIcon": { "type": { "name": "elementType" } }, + "GroupingCriteriaExpandIcon": { "type": { "name": "elementType" } }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, "LoadingOverlay": { "default": "GridLoadingOverlay", "type": { "name": "elementType" } }, "MoreActionsIcon": { "default": "GridMoreVertIcon", "type": { "name": "elementType" } }, diff --git a/docs/pages/api-docs/data-grid/data-grid.json b/docs/pages/api-docs/data-grid/data-grid.json index 6ec6f9fab4516..9bb187985e99e 100644 --- a/docs/pages/api-docs/data-grid/data-grid.json +++ b/docs/pages/api-docs/data-grid/data-grid.json @@ -184,6 +184,8 @@ "ExportIcon": { "default": "GridSaveAltIcon", "type": { "name": "elementType" } }, "FilterPanel": { "default": "GridFilterPanel", "type": { "name": "elementType" } }, "Footer": { "default": "GridFooter", "type": { "name": "elementType" } }, + "GroupingCriteriaCollapseIcon": { "type": { "name": "elementType" } }, + "GroupingCriteriaExpandIcon": { "type": { "name": "elementType" } }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, "LoadingOverlay": { "default": "GridLoadingOverlay", "type": { "name": "elementType" } }, "MoreActionsIcon": { "default": "GridMoreVertIcon", "type": { "name": "elementType" } }, diff --git a/docs/pages/api-docs/data-grid/grid-api.md b/docs/pages/api-docs/data-grid/grid-api.md index 2a7dbd3d0e5a8..018d5f540d126 100644 --- a/docs/pages/api-docs/data-grid/grid-api.md +++ b/docs/pages/api-docs/data-grid/grid-api.md @@ -10,92 +10,96 @@ import { GridApi } from '@mui/x-data-grid-pro'; ## Properties -| Name | Type | Description | -| :----------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| applySorting | () => void | Applies the current sort model to the rows. | -| commitCellChange | (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the field at the given id with the value stored in the edit row model. | -| commitRowChange | (id: GridRowId, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the row at the given id with the values stored in the edit row model. | -| deleteFilterItem | (item: GridFilterItem) => void | Deletes a GridFilterItem. | -| exportDataAsCsv | (options?: GridCsvExportOptions) => void | Downloads and exports a CSV of the grid's data. | -| exportDataAsPrint | (options?: GridPrintExportOptions) => void | Print the grid's data. | -| forceUpdate | React.Dispatch<any> | Forces the grid to rerender. It's often used after a state update. | -| getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/api/data-grid/grid-col-def/) containing all the column definitions. | -| getAllRowIds | () => GridRowId[] | Gets the list of row ids. | -| getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | -| getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | -| getCellParams | (id: GridRowId, field: string) => GridCellParams | Gets the [GridCellParams](/api/data-grid/grid-cell-params/) object that is passed as argument in events. | -| getCellValue | (id: GridRowId, field: string) => GridCellValue | Gets the value of a cell at the given `id` and `field`. | -| getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/api/data-grid/grid-col-def/) for the given `field`. | -| getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | -| getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | -| getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | -| getColumnPosition | (field: string) => number | Returns the left-position of a column relative to the inner border of the grid. | -| getColumnsMeta | () => GridColumnsMeta | Returns the GridColumnsMeta for each column. | -| getDataAsCsv | (options?: GridCsvExportOptions) => string | Returns the grid data as a CSV string.
This method is used internally by `exportDataAsCsv`. | -| getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | -| getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | -| getPinnedColumns | () => GridPinnedColumns | Returns which columns are pinned. | -| getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | -| getRow | (id: GridRowId) => GridRowModel \| null | Gets the row data with a given id. | -| getRowElement | (id: GridRowId) => HTMLDivElement \| null | Gets the underlying DOM element for a row at the given `id`. | -| getRowIdFromRowIndex | (index: number) => GridRowId | Gets the `GridRowId` of a row at a specific index.
The index is based on the sorted but unfiltered row list. | -| getRowIndex | (id: GridRowId) => number | Gets the row index of a row with a given id.
The index is based on the sorted but unfiltered row list. | -| getRowMode | (id: GridRowId) => GridRowMode | Gets the mode of a row. | -| getRowModels | () => Map<GridRowId, GridRowModel> | Gets the full set of rows as Map<GridRowId, GridRowModel>. | -| getRowNode | (id: GridRowId) => GridRowTreeNodeConfig \| null | Gets the row node from the internal tree structure. | -| getRowParams | (id: GridRowId) => GridRowParams | Gets the [GridRowParams](/api/data-grid/grid-row-params/) object that is passed as argument in events. | -| getRowsCount | () => number | Gets the total number of rows in the grid. | -| getScrollPosition | () => GridScrollParams | Returns the current scroll position. | -| getSelectedRows | () => Map<GridRowId, GridRowModel> | Returns an array of the selected rows. | -| getSortedRowIds | () => GridRowId[] | Returns all row ids sorted according to the active sort model. | -| getSortedRows | () => GridRowModel[] | Returns all rows sorted according to the active sort model. | -| getSortModel | () => GridSortModel | Returns the sort model currently applied to the grid. | -| getVisibleColumns | () => GridStateColDef[] | Returns the currently visible columns. | -| getVisibleRowModels | () => Map<GridRowId, GridRowModel> | Returns a sorted `Map` containing only the visible rows. | -| hideColumnMenu | () => void | Hides the column menu that is open. | -| hideFilterPanel | () => void | Hides the filter panel. | -| hidePreferences | () => void | Hides the preferences panel. | -| isCellEditable | (params: GridCellParams) => boolean | Controls if a cell is editable. | -| isColumnPinned | (field: string) => GridPinnedPosition \| false | Returns which side a column is pinned to. | -| isRowSelected | (id: GridRowId) => boolean | Determines if a row is selected or not. | -| pinColumn | (field: string, side: GridPinnedPosition) => void | Pins a column to the left or right side of the grid. | -| publishEvent | GridEventPublisher | Emits an event. | -| resize | () => void | Triggers a resize of the component and recalculation of width and height. | -| scroll | (params: Partial<GridScrollParams>) => void | Triggers the viewport to scroll to the given positions (in pixels). | -| scrollToIndexes | (params: Partial<GridCellIndexCoordinates>) => boolean | Triggers the viewport to scroll to the cell at indexes given by `params`.
Returns `true` if the grid had to scroll to reach the target. | -| selectRow | (id: GridRowId, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of a row. | -| selectRowRange | (range: { startId: GridRowId; endId: GridRowId }, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of all the selectable rows in a range. | -| selectRows | (ids: GridRowId[], isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of multiple rows. | -| setCellFocus | (id: GridRowId, field: string) => void | Sets the focus to the cell at the given `id` and `field`. | -| setCellMode | (id: GridRowId, field: string, mode: GridCellMode) => void | Sets the mode of a cell. | -| setColumnHeaderFocus | (field: string, event?: MuiBaseEvent) => void | Sets the focus to the column header at the given `field`. | -| setColumnIndex | (field: string, targetIndexPosition: number) => void | Moves a column from its original position to the position given by `targetIndexPosition`. | -| setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | -| setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | -| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number) => void | Sets the density of the grid. | -| setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | -| setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | -| setFilterLinkOperator | (operator: GridLinkOperator) => void | Changes the GridLinkOperator used to connect the filters. | -| setFilterModel | (model: GridFilterModel) => void | Sets the filter model to the one given by `model`. | -| setPage | (page: number) => void | Sets the displayed page to the value given by `page`. | -| setPageSize | (pageSize: number) => void | Sets the number of displayed rows to the value given by `pageSize`. | -| setPinnedColumns | (pinnedColumns: GridPinnedColumns) => void | Changes the pinned columns. | -| setRowChildrenExpansion | (id: GridRowId, isExpanded: boolean) => void | Expand or collapse a row children. | -| setRowMode | (id: GridRowId, mode: GridRowMode) => void | Sets the mode of a row. | -| setRows | (rows: GridRowModel[]) => void | Sets a new set of rows. | -| setSelectionModel | (rowIds: GridRowId[]) => void | Updates the selected rows to be those passed to the `rowIds` argument.
Any row already selected will be unselected. | -| setSortModel | (model: GridSortModel) => void | Updates the sort model and triggers the sorting of rows. | -| setState | (state: GridState \| ((previousState: GridState) => GridState)) => void | Sets the whole state of the grid. | -| showColumnMenu | (field: string) => void | Display the column menu under the `field` column. | -| showError | (props: any) => void | Displays the error overlay component. | -| showFilterPanel | (targetColumnField?: string) => void | Shows the filter panel. If `targetColumnField` is given, a filter for this field is also added. | -| showPreferences | (newValue: GridPreferencePanelsValue) => void | Displays the preferences panel. The `newValue` argument controls the content of the panel. | -| sortColumn | (column: GridColDef, direction?: GridSortDirection, allowMultipleSorting?: boolean) => void | Sorts a column. | -| state | GridState | Property that contains the whole state of the grid. | -| subscribeEvent | <E extends GridEventsStr>(event: E, handler: GridEventListener<E>, options?: EventListenerOptions) => () => void | Registers a handler for an event. | -| toggleColumnMenu | (field: string) => void | Toggles the column menu under the `field` column. | -| unpinColumn | (field: string) => void | Unpins a column. | -| updateColumn | (col: GridColDef) => void | Updates the definition of a column. | -| updateColumns | (cols: GridColDef[]) => void | Updates the definition of multiple columns at the same time. | -| updateRows | (updates: GridRowModelUpdate[]) => void | Allows to updates, insert and delete rows in a single call. | -| upsertFilterItem | (item: GridFilterItem) => void | Updates or inserts a GridFilterItem. | +| Name | Type | Description | +| :------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| addGroupingCriteria | (groupingCriteriaField: string, groupingIndex?: number) => void | Add the field to the groupingColumnsModel. | +| applySorting | () => void | Applies the current sort model to the rows. | +| commitCellChange | (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the field at the given id with the value stored in the edit row model. | +| commitRowChange | (id: GridRowId, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the row at the given id with the values stored in the edit row model. | +| deleteFilterItem | (item: GridFilterItem) => void | Deletes a GridFilterItem. | +| exportDataAsCsv | (options?: GridCsvExportOptions) => void | Downloads and exports a CSV of the grid's data. | +| exportDataAsPrint | (options?: GridPrintExportOptions) => void | Print the grid's data. | +| forceUpdate | React.Dispatch<any> | Forces the grid to rerender. It's often used after a state update. | +| getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/api/data-grid/grid-col-def/) containing all the column definitions. | +| getAllRowIds | () => GridRowId[] | Gets the list of row ids. | +| getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | +| getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | +| getCellParams | (id: GridRowId, field: string) => GridCellParams | Gets the [GridCellParams](/api/data-grid/grid-cell-params/) object that is passed as argument in events. | +| getCellValue | (id: GridRowId, field: string) => GridCellValue | Gets the value of a cell at the given `id` and `field`. | +| getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/api/data-grid/grid-col-def/) for the given `field`. | +| getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | +| getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | +| getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | +| getColumnPosition | (field: string) => number | Returns the left-position of a column relative to the inner border of the grid. | +| getColumnsMeta | () => GridColumnsMeta | Returns the GridColumnsMeta for each column. | +| getDataAsCsv | (options?: GridCsvExportOptions) => string | Returns the grid data as a CSV string.
This method is used internally by `exportDataAsCsv`. | +| getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | +| getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | +| getPinnedColumns | () => GridPinnedColumns | Returns which columns are pinned. | +| getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | +| getRow | (id: GridRowId) => GridRowModel \| null | Gets the row data with a given id. | +| getRowElement | (id: GridRowId) => HTMLDivElement \| null | Gets the underlying DOM element for a row at the given `id`. | +| getRowIdFromRowIndex | (index: number) => GridRowId | Gets the `GridRowId` of a row at a specific index.
The index is based on the sorted but unfiltered row list. | +| getRowIndex | (id: GridRowId) => number | Gets the row index of a row with a given id.
The index is based on the sorted but unfiltered row list. | +| getRowMode | (id: GridRowId) => GridRowMode | Gets the mode of a row. | +| getRowModels | () => Map<GridRowId, GridRowModel> | Gets the full set of rows as Map<GridRowId, GridRowModel>. | +| getRowNode | (id: GridRowId) => GridRowTreeNodeConfig \| null | Gets the row node from the internal tree structure. | +| getRowParams | (id: GridRowId) => GridRowParams | Gets the [GridRowParams](/api/data-grid/grid-row-params/) object that is passed as argument in events. | +| getRowsCount | () => number | Gets the total number of rows in the grid. | +| getScrollPosition | () => GridScrollParams | Returns the current scroll position. | +| getSelectedRows | () => Map<GridRowId, GridRowModel> | Returns an array of the selected rows. | +| getSortedRowIds | () => GridRowId[] | Returns all row ids sorted according to the active sort model. | +| getSortedRows | () => GridRowModel[] | Returns all rows sorted according to the active sort model. | +| getSortModel | () => GridSortModel | Returns the sort model currently applied to the grid. | +| getVisibleColumns | () => GridStateColDef[] | Returns the currently visible columns. | +| getVisibleRowModels | () => Map<GridRowId, GridRowModel> | Returns a sorted `Map` containing only the visible rows. | +| hideColumnMenu | () => void | Hides the column menu that is open. | +| hideFilterPanel | () => void | Hides the filter panel. | +| hidePreferences | () => void | Hides the preferences panel. | +| isCellEditable | (params: GridCellParams) => boolean | Controls if a cell is editable. | +| isColumnPinned | (field: string) => GridPinnedPosition \| false | Returns which side a column is pinned to. | +| isRowSelected | (id: GridRowId) => boolean | Determines if a row is selected or not. | +| pinColumn | (field: string, side: GridPinnedPosition) => void | Pins a column to the left or right side of the grid. | +| publishEvent | GridEventPublisher | Emits an event. | +| removeGroupingCriteria | (groupingCriteriaField: string) => void | Remove the field from to groupingColumnsModel. | +| resize | () => void | Triggers a resize of the component and recalculation of width and height. | +| scroll | (params: Partial<GridScrollParams>) => void | Triggers the viewport to scroll to the given positions (in pixels). | +| scrollToIndexes | (params: Partial<GridCellIndexCoordinates>) => boolean | Triggers the viewport to scroll to the cell at indexes given by `params`.
Returns `true` if the grid had to scroll to reach the target. | +| selectRow | (id: GridRowId, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of a row. | +| selectRowRange | (range: { startId: GridRowId; endId: GridRowId }, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of all the selectable rows in a range. | +| selectRows | (ids: GridRowId[], isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of multiple rows. | +| setCellFocus | (id: GridRowId, field: string) => void | Sets the focus to the cell at the given `id` and `field`. | +| setCellMode | (id: GridRowId, field: string, mode: GridCellMode) => void | Sets the mode of a cell. | +| setColumnHeaderFocus | (field: string, event?: MuiBaseEvent) => void | Sets the focus to the column header at the given `field`. | +| setColumnIndex | (field: string, targetIndexPosition: number) => void | Moves a column from its original position to the position given by `targetIndexPosition`. | +| setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | +| setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | +| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number) => void | Sets the density of the grid. | +| setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | +| setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | +| setFilterLinkOperator | (operator: GridLinkOperator) => void | Changes the GridLinkOperator used to connect the filters. | +| setFilterModel | (model: GridFilterModel) => void | Sets the filter model to the one given by `model`. | +| setGroupingColumnsModel | (model: GridGroupingColumnsModel) => void | Sets the columns to use as grouping criteria. | +| setGroupingCriteriaIndex | (groupingCriteriaField: string, groupingIndex: number) => void | Sets the grouping index of a grouping criteria. | +| setPage | (page: number) => void | Sets the displayed page to the value given by `page`. | +| setPageSize | (pageSize: number) => void | Sets the number of displayed rows to the value given by `pageSize`. | +| setPinnedColumns | (pinnedColumns: GridPinnedColumns) => void | Changes the pinned columns. | +| setRowChildrenExpansion | (id: GridRowId, isExpanded: boolean) => void | Expand or collapse a row children. | +| setRowMode | (id: GridRowId, mode: GridRowMode) => void | Sets the mode of a row. | +| setRows | (rows: GridRowModel[]) => void | Sets a new set of rows. | +| setSelectionModel | (rowIds: GridRowId[]) => void | Updates the selected rows to be those passed to the `rowIds` argument.
Any row already selected will be unselected. | +| setSortModel | (model: GridSortModel) => void | Updates the sort model and triggers the sorting of rows. | +| setState | (state: GridState \| ((previousState: GridState) => GridState)) => void | Sets the whole state of the grid. | +| showColumnMenu | (field: string) => void | Display the column menu under the `field` column. | +| showError | (props: any) => void | Displays the error overlay component. | +| showFilterPanel | (targetColumnField?: string) => void | Shows the filter panel. If `targetColumnField` is given, a filter for this field is also added. | +| showPreferences | (newValue: GridPreferencePanelsValue) => void | Displays the preferences panel. The `newValue` argument controls the content of the panel. | +| sortColumn | (column: GridColDef, direction?: GridSortDirection, allowMultipleSorting?: boolean) => void | Sorts a column. | +| state | GridState | Property that contains the whole state of the grid. | +| subscribeEvent | <E extends GridEventsStr>(event: E, handler: GridEventListener<E>, options?: EventListenerOptions) => () => void | Registers a handler for an event. | +| toggleColumnMenu | (field: string) => void | Toggles the column menu under the `field` column. | +| unpinColumn | (field: string) => void | Unpins a column. | +| updateColumn | (col: GridColDef) => void | Updates the definition of a column. | +| updateColumns | (cols: GridColDef[]) => void | Updates the definition of multiple columns at the same time. | +| updateRows | (updates: GridRowModelUpdate[]) => void | Allows to updates, insert and delete rows in a single call. | +| upsertFilterItem | (item: GridFilterItem) => void | Updates or inserts a GridFilterItem. | diff --git a/docs/pages/api-docs/data-grid/grid-col-def.md b/docs/pages/api-docs/data-grid/grid-col-def.md index acc1472582eb3..59556f655b0ef 100644 --- a/docs/pages/api-docs/data-grid/grid-col-def.md +++ b/docs/pages/api-docs/data-grid/grid-col-def.md @@ -15,6 +15,7 @@ import { GridColDef } from '@mui/x-data-grid'; | Name | Type | Default | Description | | :-------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | align? | GridAlignment | | Allows to align the column values in cells. | +| canBeGrouped? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only). | | cellClassName? | GridCellClassNamePropType | | Class name that will be added in cells for that column. | | description? | string | | The description of the column rendered as tooltip if the column header name is not fully displayed. | | disableColumnMenu? | boolean | false | If `true`, the column menu is disabled for this column. | @@ -30,6 +31,7 @@ import { GridColDef } from '@mui/x-data-grid'; | headerName? | string | | The title of the column rendered in the column header cell. | | hide? | boolean | false | If `true`, hide the column. | | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | +| keyGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transform a complex cell value into a key that be used for grouping the rows. | | minWidth? | number | 50 | Sets the minimum width of a column. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | | renderCell? | (params: GridRenderCellParams) => React.ReactNode | | Allows to override the component rendered as cell for this column. | diff --git a/docs/pages/api-docs/data-grid/grid-grouping-columns-api.json b/docs/pages/api-docs/data-grid/grid-grouping-columns-api.json new file mode 100644 index 0000000000000..e7a08af2418d9 --- /dev/null +++ b/docs/pages/api-docs/data-grid/grid-grouping-columns-api.json @@ -0,0 +1,26 @@ +{ + "name": "GridGroupingColumnsApi", + "description": "", + "properties": [ + { + "name": "addGroupingCriteria", + "description": "Add the field to the groupingColumnsModel.", + "type": "(groupingCriteriaField: string, groupingIndex?: number) => void" + }, + { + "name": "removeGroupingCriteria", + "description": "Remove the field from to groupingColumnsModel.", + "type": "(groupingCriteriaField: string) => void" + }, + { + "name": "setGroupingColumnsModel", + "description": "Sets the columns to use as grouping criteria.", + "type": "(model: GridGroupingColumnsModel) => void" + }, + { + "name": "setGroupingCriteriaIndex", + "description": "Sets the grouping index of a grouping criteria.", + "type": "(groupingCriteriaField: string, groupingIndex: number) => void" + } + ] +} diff --git a/docs/scripts/api/buildInterfacesDocumentation.ts b/docs/scripts/api/buildInterfacesDocumentation.ts index 74a72158be0a3..f80d56c1adc89 100644 --- a/docs/scripts/api/buildInterfacesDocumentation.ts +++ b/docs/scripts/api/buildInterfacesDocumentation.ts @@ -43,6 +43,7 @@ const INTERFACES_WITH_DEDICATED_PAGES = [ 'GridPrintExportOptions', 'GridScrollApi', 'GridEditRowApi', + 'GridGroupingColumnsApi', 'GridColumnPinningApi', ]; diff --git a/docs/src/pages/components/data-grid/accessibility/accessibility.md b/docs/src/pages/components/data-grid/accessibility/accessibility.md index bc38a4c3b0dfe..96cd7b33c9567 100644 --- a/docs/src/pages/components/data-grid/accessibility/accessibility.md +++ b/docs/src/pages/components/data-grid/accessibility/accessibility.md @@ -49,19 +49,20 @@ The grid responds to keyboard interactions from the user and emits events when k Use the arrow keys to move the focus. -| Keys | Description | -| -----------------------------------------------------------------: | :-------------------------------------------- | -| Arrow Left | Navigate between cell elements | -| Arrow Bottom | Navigate between cell elements | -| Arrow Right | Navigate between cell elements | -| Arrow Up | Navigate between cell elements | -| Home | Navigate to the first cell of the current row | -| End | Navigate to the last cell of the current row | -| CTRL+Home | Navigate to the first cell of the first row | -| CTRL+End | Navigate to the last cell of the last row | -| Space | Navigate to the next scrollable page | -| Page Up | Navigate to the next scrollable page | -| Page Down | Navigate to the previous scrollable page | +| Keys | Description | +| -----------------------------------------------------------------: | :---------------------------------------------------------- | +| Arrow Left | Navigate between cell elements | +| Arrow Bottom | Navigate between cell elements | +| Arrow Right | Navigate between cell elements | +| Arrow Up | Navigate between cell elements | +| Home | Navigate to the first cell of the current row | +| End | Navigate to the last cell of the current row | +| CTRL+Home | Navigate to the first cell of the first row | +| CTRL+End | Navigate to the last cell of the last row | +| Space | Navigate to the next scrollable page | +| Page Up | Navigate to the next scrollable page | +| Page Down | Navigate to the previous scrollable page | +| Space | Toggle row children expansion when grouping cell is focused | ### Selection diff --git a/docs/src/pages/components/data-grid/events/events.json b/docs/src/pages/components/data-grid/events/events.json index e95e418cfd967..ca251ff741c19 100644 --- a/docs/src/pages/components/data-grid/events/events.json +++ b/docs/src/pages/components/data-grid/events/events.json @@ -149,6 +149,12 @@ "params": "GridFilterModel", "event": "MuiEvent<{}>" }, + { + "name": "groupingColumnsModelChange", + "description": "Fired when the grouping columns model changes.", + "params": "GridGroupingColumnsModel", + "event": "MuiEvent<{}>" + }, { "name": "headerSelectionCheckboxChange", "description": "Fired when the value of the selection checkbox of the header is changed", diff --git a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.js b/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.js deleted file mode 100644 index 55130045ce945..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.js +++ /dev/null @@ -1,255 +0,0 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { - DataGridPro, - useGridApiContext, - GridEvents, - useGridSelector, - gridFilteredDescendantCountLookupSelector, -} from '@mui/x-data-grid-pro'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; - -export const isNavigationKey = (key) => - key === 'Home' || - key === 'End' || - key.indexOf('Arrow') === 0 || - key.indexOf('Page') === 0 || - key === ' '; - -const CustomGridTreeDataGroupingCell = (props) => { - const { id, field, rowNode } = props; - const apiRef = useGridApiContext(); - const filteredDescendantCountLookup = useGridSelector( - apiRef, - gridFilteredDescendantCountLookupSelector, - ); - - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - - const handleKeyDown = (event) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); - } - }; - - const handleClick = (event) => { - apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); - apiRef.current.setCellFocus(id, field); - event.stopPropagation(); - }; - - return ( - -
- {filteredDescendantCount > 0 ? ( - - ) : ( - - )} -
-
- ); -}; - -CustomGridTreeDataGroupingCell.propTypes = { - /** - * The column field of the cell that triggered the event. - */ - field: PropTypes.string.isRequired, - /** - * The grid row id. - */ - id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - /** - * The node of the row that the current cell belongs to. - */ - rowNode: PropTypes.shape({ - /** - * The id of the row children. - */ - children: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - ), - /** - * Current expansion status of the row. - */ - childrenExpanded: PropTypes.bool, - /** - * 0-based depth of the row in the tree. - */ - depth: PropTypes.number.isRequired, - /** - * The field used to group the children of this row. - * Is `null` if no field has been used to group the children of this row. - */ - groupingField: PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.string]) - .isRequired, - /** - * The key used to group the children of this row. - */ - groupingKey: PropTypes.oneOfType([ - PropTypes.number, - PropTypes.string, - PropTypes.bool, - ]).isRequired, - /** - * The grid row id. - */ - id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - /** - * If `true`, this node has been automatically added to fill a gap in the tree structure. - */ - isAutoGenerated: PropTypes.bool, - /** - * The row id of the parent (null if this row is a top level row). - */ - parent: PropTypes.oneOfType([ - PropTypes.oneOf([null]), - PropTypes.number, - PropTypes.string, - ]).isRequired, - }).isRequired, -}; - -const rows = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns = [ - { - field: 'name', - headerName: 'Name', - valueGetter: (params) => { - const hierarchy = params.row.hierarchy; - return hierarchy[hierarchy.length - 1]; - }, - }, - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -const groupingColDef = { - headerName: 'Hierarchy', - renderCell: (params) => , -}; - -export default function CustomGroupingColumnTreeData() { - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx b/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx deleted file mode 100644 index 062332c624a1a..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx +++ /dev/null @@ -1,197 +0,0 @@ -import * as React from 'react'; -import { - DataGridPro, - GridRenderCellParams, - useGridApiContext, - GridEvents, - GridColumns, - GridRowsProp, - DataGridProProps, - useGridSelector, - gridFilteredDescendantCountLookupSelector, -} from '@mui/x-data-grid-pro'; -import Box from '@mui/material/Box'; -import Button from '@mui/material/Button'; - -export const isNavigationKey = (key: string) => - key === 'Home' || - key === 'End' || - key.indexOf('Arrow') === 0 || - key.indexOf('Page') === 0 || - key === ' '; - -const CustomGridTreeDataGroupingCell = (props: GridRenderCellParams) => { - const { id, field, rowNode } = props; - const apiRef = useGridApiContext(); - const filteredDescendantCountLookup = useGridSelector( - apiRef, - gridFilteredDescendantCountLookupSelector, - ); - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - - const handleKeyDown = (event) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); - } - }; - - const handleClick = (event) => { - apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); - apiRef.current.setCellFocus(id, field); - event.stopPropagation(); - }; - - return ( - -
- {filteredDescendantCount > 0 ? ( - - ) : ( - - )} -
-
- ); -}; - -const rows: GridRowsProp = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns: GridColumns = [ - { - field: 'name', - headerName: 'Name', - valueGetter: (params) => { - const hierarchy = params.row.hierarchy as string[]; - return hierarchy[hierarchy.length - 1]; - }, - }, - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -const groupingColDef: DataGridProProps['groupingColDef'] = { - headerName: 'Hierarchy', - renderCell: (params) => , -}; - -export default function CustomGroupingColumnTreeData() { - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx.preview deleted file mode 100644 index 35b9b522e32e6..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.tsx.preview +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.js b/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.js deleted file mode 100644 index 61a48100c6b66..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.js +++ /dev/null @@ -1,121 +0,0 @@ -import * as React from 'react'; -import { DataGridPro } from '@mui/x-data-grid-pro'; - -const rows = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns = [ - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -export default function DefaultGroupingExpansionDepthTreeData() { - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx b/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx deleted file mode 100644 index 4b43a12797a74..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import * as React from 'react'; -import { DataGridPro, GridColumns, GridRowsProp } from '@mui/x-data-grid-pro'; - -const rows: GridRowsProp = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns: GridColumns = [ - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -export default function DefaultGroupingExpansionDepthTreeData() { - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx.preview deleted file mode 100644 index e907316a9015d..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.tsx.preview +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js new file mode 100644 index 0000000000000..06a1f387f40d4 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js @@ -0,0 +1,7 @@ +import React from 'react'; +import ApiDocs from 'docsx/src/modules/components/ApiDocs'; +import api from 'docsx/pages/api-docs/data-grid/grid-grouping-columns-api.json'; + +export default function GroupingColumnsApiNoSnap() { + return ; +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js new file mode 100644 index 0000000000000..d7bf8272e9d9e --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsColDefCanBeGrouped() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const columnWithNoDirectorGroup = React.useMemo( + () => + columns.map((colDef) => + colDef.field === 'director' ? { ...colDef, canBeGrouped: false } : colDef, + ), + [columns], + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx new file mode 100644 index 0000000000000..0b8c1550e104a --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx @@ -0,0 +1,87 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsColDefCanBeGrouped() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const columnWithNoDirectorGroup = React.useMemo( + () => + columns.map((colDef) => + colDef.field === 'director' ? { ...colDef, canBeGrouped: false } : colDef, + ), + [columns], + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview new file mode 100644 index 0000000000000..16342c14b0a8b --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js new file mode 100644 index 0000000000000..fa8f6d017ffbc --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsControlled() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ setGroupingColumnsModel(model)} + experimentalFeatures={{ + groupingColumns: true, + }} + /> +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx new file mode 100644 index 0000000000000..b8eaed92f92b6 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx @@ -0,0 +1,78 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsControlled() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const [groupingColumnsModel, setGroupingColumnsModel] = + React.useState(INITIAL_GROUPING_COLUMN_MODEL); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ setGroupingColumnsModel(model)} + experimentalFeatures={{ + groupingColumns: true, + }} + /> +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview new file mode 100644 index 0000000000000..52b1567caaefa --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview @@ -0,0 +1,10 @@ + setGroupingColumnsModel(model)} + experimentalFeatures={{ + groupingColumns: true, + }} +/> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js new file mode 100644 index 0000000000000..b1f1f6ecc6a77 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js @@ -0,0 +1,102 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Chip from '@mui/material/Chip'; +import Box from '@mui/material/Box'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsCustomGroupingColDefCallback() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const groupingColumnsModelStr = groupingColumnsModel.join('-'); + + return ( +
+ + setGroupingColumnsModel(['company'])} + variant="outlined" + color={groupingColumnsModelStr === 'company' ? 'primary' : undefined} + /> + setGroupingColumnsModel(['company', 'director'])} + variant="outlined" + color={ + groupingColumnsModelStr === 'company-director' ? 'primary' : undefined + } + /> + + + + params.fields.includes('director') + ? { + headerName: 'Director', + } + : {} + } + experimentalFeatures={{ + groupingColumns: true, + }} + /> + +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx new file mode 100644 index 0000000000000..237a972b8c585 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx @@ -0,0 +1,113 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Chip from '@mui/material/Chip'; +import Box from '@mui/material/Box'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsCustomGroupingColDefCallback() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const groupingColumnsModelStr = groupingColumnsModel.join('-'); + + return ( +
+ + setGroupingColumnsModel(['company'])} + variant="outlined" + color={groupingColumnsModelStr === 'company' ? 'primary' : undefined} + /> + setGroupingColumnsModel(['company', 'director'])} + variant="outlined" + color={ + groupingColumnsModelStr === 'company-director' ? 'primary' : undefined + } + /> + + + + params.fields.includes('director') + ? { + headerName: 'Director', + } + : {} + } + experimentalFeatures={{ + groupingColumns: true, + }} + /> + +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js new file mode 100644 index 0000000000000..3dce1cbd4f729 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsCustomGroupingColDefObject() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx new file mode 100644 index 0000000000000..b19bd4470b37a --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx @@ -0,0 +1,82 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsCustomGroupingColDefObject() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js new file mode 100644 index 0000000000000..f3146d295b997 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsDefaultExpansionDepth() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx new file mode 100644 index 0000000000000..2421a7ced51f5 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsDefaultExpansionDepth() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview new file mode 100644 index 0000000000000..134059cd85437 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js new file mode 100644 index 0000000000000..19f0dca8f3da3 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { DataGridPro } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +export default function GroupingColumnsDisabled() { + const data = useMovieData(); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx new file mode 100644 index 0000000000000..19f0dca8f3da3 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { DataGridPro } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +export default function GroupingColumnsDisabled() { + const data = useMovieData(); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview new file mode 100644 index 0000000000000..a33ed2d386560 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js new file mode 100644 index 0000000000000..7e058768baabd --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js @@ -0,0 +1,80 @@ +import { useDemoData } from '@mui/x-data-grid-generator'; +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['commodity']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsFullExample() { + const { data, loading } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 25, + }); + + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx new file mode 100644 index 0000000000000..dd3169421b240 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx @@ -0,0 +1,90 @@ +import { useDemoData } from '@mui/x-data-grid-generator'; +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['commodity']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsFullExample() { + const { data, loading } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 25, + }); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js new file mode 100644 index 0000000000000..09ca5a53d88bb --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsHideDescendantCount() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx new file mode 100644 index 0000000000000..390c14bf81743 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx @@ -0,0 +1,82 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsHideDescendantCount() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js new file mode 100644 index 0000000000000..c430127e89ae6 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsInitialState() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx new file mode 100644 index 0000000000000..53e63ccb42388 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsInitialState() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview new file mode 100644 index 0000000000000..d8316eba2e773 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js new file mode 100644 index 0000000000000..cc986dffe008a --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['composer']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsKeyGetter() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columnsWithComposer = React.useMemo( + () => [ + ...data.columns, + { + field: 'composer', + headerName: 'Composer', + renderCell: (params) => params.value?.name, + keyGetter: (params) => params.value.name, + width: 200, + }, + ], + [data.columns], + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + columnsWithComposer, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx new file mode 100644 index 0000000000000..543232954bbde --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx @@ -0,0 +1,96 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + GridKeyGetterParams, + GridRenderCellParams, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['composer']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsKeyGetter() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columnsWithComposer = React.useMemo( + () => [ + ...data.columns, + { + field: 'composer', + headerName: 'Composer', + renderCell: (params: GridRenderCellParams<{ name: string } | undefined>) => + params.value?.name, + keyGetter: (params: GridKeyGetterParams<{ name: string }>) => + params.value.name, + width: 200, + }, + ], + [data.columns], + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + columnsWithComposer, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview new file mode 100644 index 0000000000000..9551cf41a1467 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js new file mode 100644 index 0000000000000..8b3ddb57234ea --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js @@ -0,0 +1,92 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['decade']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsKeyGetterValueGetter() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columnsWithDecade = React.useMemo( + () => [ + ...data.columns, + { + field: 'decade', + headerName: 'Decade', + valueGetter: (params) => { + const value = Math.floor(params.row.year / 10) * 10; + + if (params.row.year == null) { + return null; + } + + return { + value, + name: `${value.toString().slice(-2)}'s`, + }; + }, + keyGetter: (params) => params.value?.value, + renderCell: (params) => params.value?.name, + }, + ], + [data.columns], + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + columnsWithDecade, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx new file mode 100644 index 0000000000000..fee7809ae7eb0 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx @@ -0,0 +1,109 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + GridKeyGetterParams, + GridRenderCellParams, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +type Decade = { value: number; name: string }; + +const INITIAL_GROUPING_COLUMN_MODEL = ['decade']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsKeyGetterValueGetter() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columnsWithDecade = React.useMemo( + () => [ + ...data.columns, + { + field: 'decade', + headerName: 'Decade', + valueGetter: (params): Decade | null => { + const value = Math.floor(params.row.year / 10) * 10; + + if (params.row.year == null) { + return null; + } + + return { + value, + name: `${value.toString().slice(-2)}'s`, + }; + }, + keyGetter: (params: GridKeyGetterParams) => + params.value?.value, + renderCell: (params: GridRenderCellParams) => + params.value?.name, + }, + ], + [data.columns], + ); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + columnsWithDecade, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview new file mode 100644 index 0000000000000..9551cf41a1467 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js new file mode 100644 index 0000000000000..2b2bc132c7a9e --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsLeafWithValue() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + 'title', + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx new file mode 100644 index 0000000000000..8a15f65ed3740 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsLeafWithValue() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + 'title', + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview new file mode 100644 index 0000000000000..019f7e08baea6 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js new file mode 100644 index 0000000000000..7d3c32b1e51a0 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsMultipleGroupingCol() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx new file mode 100644 index 0000000000000..acfd63edcf800 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsMultipleGroupingCol() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview new file mode 100644 index 0000000000000..14a6fdea76cd5 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js new file mode 100644 index 0000000000000..4751accb689c5 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['cinematicUniverse']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsRowsWithMissingGroups() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx new file mode 100644 index 0000000000000..ec7a94fde0a44 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['cinematicUniverse']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsRowsWithMissingGroups() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview new file mode 100644 index 0000000000000..d8316eba2e773 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js new file mode 100644 index 0000000000000..fc09f030b4bb6 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js @@ -0,0 +1,90 @@ +import * as React from 'react'; +import { + DataGridPro, + GridEvents, + gridVisibleSortedRowIdsSelector, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSetChildrenExpansion() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const toggleSecondRow = () => { + const rowIds = gridVisibleSortedRowIdsSelector(apiRef.current.state); + + if (rowIds.length > 1) { + const rowId = rowIds[1]; + apiRef.current.setRowChildrenExpansion( + rowId, + !apiRef.current.getRowNode(rowId)?.childrenExpanded, + ); + } + }; + + return ( + + +
+ +
+
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx new file mode 100644 index 0000000000000..3dba60920bb81 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + gridVisibleSortedRowIdsSelector, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import Button from '@mui/material/Button'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSetChildrenExpansion() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + const toggleSecondRow = () => { + const rowIds = gridVisibleSortedRowIdsSelector(apiRef.current.state); + + if (rowIds.length > 1) { + const rowId = rowIds[1]; + apiRef.current.setRowChildrenExpansion( + rowId, + !apiRef.current.getRowNode(rowId)?.childrenExpanded, + ); + } + }; + + return ( + + +
+ +
+
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js new file mode 100644 index 0000000000000..8c20f0833f58c --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js @@ -0,0 +1,68 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSingleGroupingCol() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx new file mode 100644 index 0000000000000..1a4405b8d19fa --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx @@ -0,0 +1,79 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSingleGroupingCol() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview new file mode 100644 index 0000000000000..3bade81ba2f19 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js new file mode 100644 index 0000000000000..d203e7113bcda --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js @@ -0,0 +1,78 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSortingMultipleGroupingColDef() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ + params.fields.includes('director') + ? { + leafField: 'title', + mainGroupingCriteria: 'director', + } + : {} + } + experimentalFeatures={{ + groupingColumns: true, + }} + /> +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx new file mode 100644 index 0000000000000..dcf3070051c90 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx @@ -0,0 +1,89 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSortingMultipleGroupingColDef() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ + params.fields.includes('director') + ? { + leafField: 'title', + mainGroupingCriteria: 'director', + } + : {} + } + experimentalFeatures={{ + groupingColumns: true, + }} + /> +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js new file mode 100644 index 0000000000000..77ad049c91460 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js @@ -0,0 +1,105 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import InputLabel from '@mui/material/InputLabel'; +import Select from '@mui/material/Select'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSortingSingleGroupingColDef() { + const data = useMovieData(); + const [mainGroupingCriteria, setMainGroupingCriteria] = + React.useState('undefined'); + + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( + + + + Main Grouping Criteria + + + +
+ +
+
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx new file mode 100644 index 0000000000000..be42d5e616e6c --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx @@ -0,0 +1,116 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridGroupingColumnsModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; +import Stack from '@mui/material/Stack'; +import MenuItem from '@mui/material/MenuItem'; +import FormControl from '@mui/material/FormControl'; +import InputLabel from '@mui/material/InputLabel'; +import Select from '@mui/material/Select'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridGroupingColumnsModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent( + GridEvents.groupingColumnsModelChange, + (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }, + ); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function GroupingColumnsSortingSingleGroupingColDef() { + const data = useMovieData(); + const [mainGroupingCriteria, setMainGroupingCriteria] = + React.useState('undefined'); + + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( + + + + Main Grouping Criteria + + + +
+ +
+
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.js b/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.js deleted file mode 100644 index 25a936898a2ec..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.js +++ /dev/null @@ -1,145 +0,0 @@ -import * as React from 'react'; -import { - DataGridPro, - useGridApiRef, - gridVisibleSortedRowIdsSelector, -} from '@mui/x-data-grid-pro'; -import Stack from '@mui/material/Stack'; -import Button from '@mui/material/Button'; - -const rows = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns = [ - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -export default function SetRowExpansionTreeData() { - const apiRef = useGridApiRef(); - - const toggleSecondRow = () => { - const rowIds = gridVisibleSortedRowIdsSelector(apiRef.current.state); - - if (rows.length > 1) { - const rowId = rowIds[1]; - apiRef.current.setRowChildrenExpansion( - rowId, - !apiRef.current.getRowNode(rowId)?.childrenExpanded, - ); - } - }; - - return ( - - -
- -
-
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx b/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx deleted file mode 100644 index 2512e502342c5..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import * as React from 'react'; -import { - DataGridPro, - GridColumns, - GridRowsProp, - useGridApiRef, - gridVisibleSortedRowIdsSelector, -} from '@mui/x-data-grid-pro'; -import Stack from '@mui/material/Stack'; -import Button from '@mui/material/Button'; - -const rows: GridRowsProp = [ - { - hierarchy: ['Sarah'], - jobTitle: 'Head of Human Resources', - recruitmentDate: new Date(2020, 8, 12), - id: 0, - }, - { - hierarchy: ['Thomas'], - jobTitle: 'Head of Sales', - recruitmentDate: new Date(2017, 3, 4), - id: 1, - }, - { - hierarchy: ['Thomas', 'Robert'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 11, 20), - id: 2, - }, - { - hierarchy: ['Thomas', 'Karen'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 10, 14), - id: 3, - }, - { - hierarchy: ['Thomas', 'Nancy'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2017, 10, 29), - id: 4, - }, - { - hierarchy: ['Thomas', 'Daniel'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 21), - id: 5, - }, - { - hierarchy: ['Thomas', 'Christopher'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2020, 7, 20), - id: 6, - }, - { - hierarchy: ['Thomas', 'Donald'], - jobTitle: 'Sales Person', - recruitmentDate: new Date(2019, 6, 28), - id: 7, - }, - { - hierarchy: ['Mary'], - jobTitle: 'Head of Engineering', - recruitmentDate: new Date(2016, 3, 14), - id: 8, - }, - { - hierarchy: ['Mary', 'Jennifer'], - jobTitle: 'Tech lead front', - recruitmentDate: new Date(2016, 5, 17), - id: 9, - }, - { - hierarchy: ['Mary', 'Jennifer', 'Anna'], - jobTitle: 'Front-end developer', - recruitmentDate: new Date(2019, 11, 7), - id: 10, - }, - { - hierarchy: ['Mary', 'Michael'], - jobTitle: 'Tech lead devops', - recruitmentDate: new Date(2021, 7, 1), - id: 11, - }, - { - hierarchy: ['Mary', 'Linda'], - jobTitle: 'Tech lead back', - recruitmentDate: new Date(2017, 0, 12), - id: 12, - }, - { - hierarchy: ['Mary', 'Linda', 'Elizabeth'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2019, 2, 22), - id: 13, - }, - { - hierarchy: ['Mary', 'Linda', 'William'], - jobTitle: 'Back-end developer', - recruitmentDate: new Date(2018, 4, 19), - id: 14, - }, -]; - -const columns: GridColumns = [ - { field: 'jobTitle', headerName: 'Job Title', width: 200 }, - { - field: 'recruitmentDate', - headerName: 'Recruitment Date', - type: 'date', - width: 150, - }, -]; - -const getTreeDataPath = (row) => row.hierarchy; - -export default function SetRowExpansionTreeData() { - const apiRef = useGridApiRef(); - - const toggleSecondRow = () => { - const rowIds = gridVisibleSortedRowIdsSelector(apiRef.current.state); - - if (rows.length > 1) { - const rowId = rowIds[1]; - apiRef.current.setRowChildrenExpansion( - rowId, - !apiRef.current.getRowNode(rowId)?.childrenExpanded, - ); - } - }; - - return ( - - -
- -
-
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx.preview deleted file mode 100644 index 68347f54d4626..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/SetRowExpansionTreeData.tsx.preview +++ /dev/null @@ -1,11 +0,0 @@ - -
- -
\ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.js b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.js similarity index 98% rename from docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.js rename to docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.js index a608d8b716c14..d862ec6cee6f1 100644 --- a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.js +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.js @@ -111,7 +111,7 @@ const columns = [ const getTreeDataPath = (row) => row.hierarchy; -export default function DisableChildrenFilteringTreeData() { +export default function TreeDataDisableChildrenFiltering() { const [disableChildrenFiltering, setDisableChildrenFiltering] = React.useState(true); const [filterModel, setFilterModel] = React.useState({ diff --git a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.tsx b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.tsx similarity index 98% rename from docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.tsx rename to docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.tsx index 256e8a37a8f8d..af50f02481177 100644 --- a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.tsx @@ -117,7 +117,7 @@ const columns: GridColumns = [ const getTreeDataPath = (row) => row.hierarchy; -export default function DisableChildrenFilteringTreeData() { +export default function TreeDataDisableChildrenFiltering() { const [disableChildrenFiltering, setDisableChildrenFiltering] = React.useState(true); const [filterModel, setFilterModel] = React.useState({ diff --git a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.js b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.js similarity index 98% rename from docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.js rename to docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.js index 19e5fadc359d8..871b4ed1748b9 100644 --- a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.js +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.js @@ -111,7 +111,7 @@ const columns = [ const getTreeDataPath = (row) => row.hierarchy; -export default function DisableChildrenSortingTreeData() { +export default function TreeDataDisableChildrenSorting() { const [disableChildrenSorting, setDisableChildrenSorting] = React.useState(true); const [sortModel, setSortModel] = React.useState([ { field: 'recruitmentDate', sort: 'asc' }, diff --git a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.tsx b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.tsx similarity index 98% rename from docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.tsx rename to docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.tsx index 012a19e36a291..fdd25abcfae7f 100644 --- a/docs/src/pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.tsx @@ -116,7 +116,7 @@ const columns: GridColumns = [ const getTreeDataPath = (row) => row.hierarchy; -export default function DisableChildrenSortingTreeData() { +export default function TreeDataDisableChildrenSorting() { const [disableChildrenSorting, setDisableChildrenSorting] = React.useState(true); const [sortModel, setSortModel] = React.useState([ { field: 'recruitmentDate', sort: 'asc' }, diff --git a/docs/src/pages/components/data-grid/group-pivot/BasicTreeData.js b/docs/src/pages/components/data-grid/group-pivot/TreeDataSimple.js similarity index 98% rename from docs/src/pages/components/data-grid/group-pivot/BasicTreeData.js rename to docs/src/pages/components/data-grid/group-pivot/TreeDataSimple.js index b53e0acbb0e05..616037c4fcdae 100644 --- a/docs/src/pages/components/data-grid/group-pivot/BasicTreeData.js +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataSimple.js @@ -106,7 +106,7 @@ const columns = [ const getTreeDataPath = (row) => row.hierarchy; -export default function BasicTreeData() { +export default function TreeDataSimple() { return (
row.hierarchy; -export default function BasicTreeData() { +export default function TreeDataSimple() { return (
Use grouping, pivoting, and more to analyze the data in depth.

+## Grouping Columns [](https://mui.com/store/items/material-ui-pro/) + +Use grouping columns to group the rows according to one or several columns value

+ +> ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. +> +> To avoid future regression for users of the Pro plan, the feature needs to be explicitly activated using the `groupingColumns` experimental feature flag. +> +> ```tsx +> +> ``` +> +> The feature is stable in its current form, and we encourage users willing to migrate to the Premium plan once available to start using it. + +### Grouping columns definition + +#### Initializing the grouping columns + +To initialize the grouping columns without controlling them, provide the model to the `initialState` prop: + +```ts +initialState={{ + groupingColumns: { + model: ['director', 'category'] + } +}} +``` + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Controlling the grouping columns + +To fully control the grouping columns, provide the model to the `groupingColumnsModel` prop. +Use it together with `onGroupingColumnsModelChange` to know when a grouping criteria is added or removed. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsControlled.js", "bg": "inline", "defaultCodeOpen": false}} + +### Disable the grouping + +#### Fully disable the grouping + +To fully disable the grouping feature, set the `disableGroupingColumns` prop to `true`. + +It will disable all the features related to the grouping columns, even if a model is provided. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Disable the grouping for some columns + +To block the grouping of certain columns, set the `canBeGrouped` property of `GridColDef` to `false`. +In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Single grouping column + +By default, the grid will create only one grouping column even if you have several grouping criteria. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Multiple grouping column + +To have a grouping column for each grouping criteria, set the `groupingColumnMode` prop to `multiple`. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} + +### Grouping column customization + +Use the `groupingColDef` prop to customize the rendering of the grouping column. You can override any property of the `GridColDef` interface except the `field`, the `type` and the properties related to the edition. + +If you want to apply your overrides to every grouping column, use the object format of `groupingColDef`. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js", "bg": "inline", "defaultCodeOpen": false}} + +If you want to only override properties of certain grouping columns or to apply different overrides based on the current grouping criteria, use the callback format of `groupingColDef`. +It will be called for each grouping column with the fields of the columns used to build it. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Show values for the leaves + +By default, the leaves nodes don't render anything for their grouping cell. + +If you want to display some value, you can provide a `leafField` property to the `groupingColDef`. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Hide the descendant count + +You can use the `hideDescendantCount` property of the `groupingColDef` to hide the amount of descendant of a grouping row. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js", "bg": "inline", "defaultCodeOpen": false}} + +### Complex grouping value + +In most scenarios, when you need to handle complex values, you provide a `valueGetter` property to your column definition. +But sometimes, you need to keep the object format for the `renderCell` property and thus can not convert it to a serializable value in `valueGetter`. + +You can then provide a `keyGetter` property in your column definition to convert this object into a serializable value. + +```ts +const columns: GridColumns = [ + { + field: 'composer', + keyGetter: (params) => params.value.name, + }, + // ... +]; +``` + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js", "bg": "inline", "defaultCodeOpen": false}} + +If your column also have a `valueGetter` property, the value passed to the `keyGetter` property will be the one returned by `valueGetter`. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} + +### Rows with missing groups + +If the grouping key of a grouping criteria is `null` or `undefined` for a row, the grid will consider that this row do not have a value for this group. and will inline it for those groups. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js", "bg": "inline", "defaultCodeOpen": false}} + +### Group expansion + +Use the `defaultGroupingExpansionDepth` prop to expand all the groups up to a given depth when loading the data. +If you want to expand the whole tree, set `defaultGroupingExpansionDepth = -1` + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js", "bg": "inline", "defaultCodeOpen": false}} + +Use the `setRowChildrenExpansion` method on `apiRef` to programmatically set the expansion of a row. + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js", "bg": "inline", "defaultCodeOpen": false}} + +### Sorting / Filtering + +#### Single grouping column + +When using `groupingColumnMode = "single"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the top level grouping criteria. + +If you are rendering leaves with the `leafField` property of `groupColDef`, the sorting and filtering will be applied on the leaves based on the `sortComparator` and `filterOperators` of their original column. + +In both cases, you can force the sorting and filtering to be applied on another grouping criteria with the `mainGroupingCriteria` property of `groupColDef` + +> ⚠️ This feature is not yet compatible with `sortingMode = "server` and `filteringMode = "server"` + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} + +#### Multiple grouping column + +When using `groupingColumnMode = "multiple"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the grouping criteria of each grouping column. + +If you are rendering leaves on one of those columns with the `leafField` property of `groupColDef`, the sorting and filtering will be applied on the leaves for this grouping column based on the `sortComparator` and `filterOperators` of the leave's original column. + +If you want to render leaves but apply the sorting and filtering on the grouping criteria of the column, you can force it by setting the `mainGroupingCriteria` property `groupColDef` to be equal to the grouping criteria. + +In the example below: + +- the sorting and filtering of the `company` grouping column is applied on the `company` field +- the sorting and filtering of the `director` grouping column is applied on the `director` field even though it has leaves + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} + +> ⚠️ If you are dynamically switching the `leafField` or `mainGroupingCriteria`, the sorting and filtering models will not automatically be cleaned-up and the sorting / filtering will not be re-applied. + +### Full example + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js", "bg": "inline", "defaultCodeOpen": false}} + +### apiRef [](https://mui.com/store/items/material-ui-pro/) + +{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js", "bg": "inline", "hideToolbar": true}} + ## Tree Data [](https://mui.com/store/items/material-ui-pro/) Tree Data allows to display data with parent/child relationships. @@ -53,24 +225,15 @@ const rows: GridRowsProp = [ />; ``` -{{"demo": "pages/components/data-grid/group-pivot/BasicTreeData.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/TreeDataSimple.js", "bg": "inline", "defaultCodeOpen": false}} -### Custom grouping column +### Grouping column customization -Use the `groupingColDef` prop to customize the rendering of the grouping column. - -{{"demo": "pages/components/data-grid/group-pivot/CustomGroupingColumnTreeData.js", "bg": "inline", "defaultCodeOpen": false}} +Same behavior as for the [Grouping Columns](##grouping-column-customization) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. ### Group expansion -Use the `defaultGroupingExpansionDepth` prop to expand all the groups up to a given depth when loading the data. -If you want to expand the whole tree, set `defaultGroupingExpansionDepth = -1` - -{{"demo": "pages/components/data-grid/group-pivot/DefaultGroupingExpansionDepthTreeData.js", "bg": "inline", "defaultCodeOpen": false}} - -Use the `setRowChildrenExpansion` method on `apiRef` to programmatically set the expansion of a row. - -{{"demo": "pages/components/data-grid/group-pivot/SetRowExpansionTreeData.js", "bg": "inline", "defaultCodeOpen": false}} +Same behavior as for the [Grouping Columns](#group-expansion) ### Gaps in the tree @@ -88,14 +251,14 @@ A node is included if one of the following criteria is met: By default, the filtering is applied to every depth of the tree. You can limit the filtering to the top-level rows with the `disableChildrenFiltering` prop. -{{"demo": "pages/components/data-grid/group-pivot/DisableChildrenFilteringTreeData.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/TreeDataDisableChildrenFiltering.js", "bg": "inline", "defaultCodeOpen": false}} ### Sorting By default, the sorting is applied to every depth of the tree. You can limit the sorting to the top level rows with the `disableChildrenSorting` prop. -{{"demo": "pages/components/data-grid/group-pivot/DisableChildrenSortingTreeData.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/TreeDataDisableChildrenSorting.js", "bg": "inline", "defaultCodeOpen": false}} > If you are using `sortingMode="server"`, you need to always put the children of a row after its parent. > For instance: @@ -120,14 +283,6 @@ You can limit the sorting to the top level rows with the `disableChildrenSorting The feature allows to display row details on an expandable pane. -## 🚧 Grouping [](https://mui.com/store/items/material-ui-pro/) - -> ⚠️ This feature isn't implemented yet. It's coming. -> -> 👍 Upvote [issue #212](https://github.com/mui-org/material-ui-x/issues/212) if you want to see it land faster. - -Group rows together that share a column value, this creates a visible header for each group and allows the end-user to collapse groups that they don't want to see. - ## 🚧 Aggregation [](https://mui.com/store/items/material-ui-pro/) > ⚠️ This feature isn't implemented yet. It's coming. diff --git a/docs/src/pages/components/data-grid/overview/overview.md b/docs/src/pages/components/data-grid/overview/overview.md index 5beda0ad30bc1..71b8f6336f369 100644 --- a/docs/src/pages/components/data-grid/overview/overview.md +++ b/docs/src/pages/components/data-grid/overview/overview.md @@ -78,6 +78,7 @@ We provide three options: - [Selection](/components/data-grid/selection/) - [Column virtualization](/components/data-grid/virtualization/#column-virtualization) and [rows virtualization](/components/data-grid/virtualization/#row-virtualization) - [Tree data](/components/data-grid/group-pivot/#tree-data) +- [Grouping columns](/components/data-grid/grouping-columns) - [Resizable columns](/components/data-grid/columns/#column-resizing) - [100% customizable](/components/data-grid/style/) - Server-side data @@ -94,7 +95,7 @@ While development of the data grid component is moving fast, there are still man - [Column pinning](/components/data-grid/columns/#column-pinning) - [Excel export](/components/data-grid/export/) - [Range selection](/components/data-grid/selection/#range-selection) -- [Group, Pivot, Aggregation](/components/data-grid/group-pivot/) +- [Pivot, Aggregation](/components/data-grid/group-pivot/) You can find more details on, the [feature comparison](/components/data-grid/getting-started/#feature-comparison), our living quarterly [roadmap](https://github.com/mui-org/material-ui-x/projects/1) as well as on the open [GitHub issues](https://github.com/mui-org/material-ui-x/issues?q=is%3Aopen+label%3A%22component%3A+DataGrid%22+label%3Aenhancement). diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index 872329dcc1386..6c821c8de6705 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -17,8 +17,8 @@ "componentsProps": "Overrideable components props dynamically passed to the component at rendering.", "defaultGroupingExpansionDepth": "If above 0, the row children will be expanded up to this depth. If equal to -1, all the row children will be expanded.", "density": "Set the density of the grid.", - "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows.", - "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows.", + "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows when grouping rows with the treeData prop.", + "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows when grouping rows with the treeData prop.", "disableColumnFilter": "If true, column filters are disabled.", "disableColumnMenu": "If true, the column menu is disabled.", "disableColumnPinning": "If true, the column pinning is disabled.", @@ -27,6 +27,7 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", + "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", @@ -35,6 +36,7 @@ "editMode": "Controls whether to use the cell or row editing.", "editRowsModel": "Set the edit rows model of the grid.", "error": "An error that will turn the grid into its error state and display the error component.", + "experimentalFeatures": "Features under development. For each feature, if the flag is not explicitly set to true, the feature will be fully disabled and any property / method call will not have any effect.", "filterMode": "Filtering can be processed on the server or client-side. Set it to 'server' if you would like to handle filtering on the server-side.", "filterModel": "Set the filter model of the grid.", "getCellClassName": "Function that applies CSS classes dynamically on cells.

Signature:
function(params: GridCellParams) => string
params: With all properties from GridCellParams.
returns (string): The CSS class to apply to the cell.", @@ -42,6 +44,8 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -76,6 +80,7 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", + "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -445,6 +450,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index 872329dcc1386..6c821c8de6705 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -17,8 +17,8 @@ "componentsProps": "Overrideable components props dynamically passed to the component at rendering.", "defaultGroupingExpansionDepth": "If above 0, the row children will be expanded up to this depth. If equal to -1, all the row children will be expanded.", "density": "Set the density of the grid.", - "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows.", - "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows.", + "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows when grouping rows with the treeData prop.", + "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows when grouping rows with the treeData prop.", "disableColumnFilter": "If true, column filters are disabled.", "disableColumnMenu": "If true, the column menu is disabled.", "disableColumnPinning": "If true, the column pinning is disabled.", @@ -27,6 +27,7 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", + "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", @@ -35,6 +36,7 @@ "editMode": "Controls whether to use the cell or row editing.", "editRowsModel": "Set the edit rows model of the grid.", "error": "An error that will turn the grid into its error state and display the error component.", + "experimentalFeatures": "Features under development. For each feature, if the flag is not explicitly set to true, the feature will be fully disabled and any property / method call will not have any effect.", "filterMode": "Filtering can be processed on the server or client-side. Set it to 'server' if you would like to handle filtering on the server-side.", "filterModel": "Set the filter model of the grid.", "getCellClassName": "Function that applies CSS classes dynamically on cells.

Signature:
function(params: GridCellParams) => string
params: With all properties from GridCellParams.
returns (string): The CSS class to apply to the cell.", @@ -42,6 +44,8 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -76,6 +80,7 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", + "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -445,6 +450,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index 872329dcc1386..6c821c8de6705 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -17,8 +17,8 @@ "componentsProps": "Overrideable components props dynamically passed to the component at rendering.", "defaultGroupingExpansionDepth": "If above 0, the row children will be expanded up to this depth. If equal to -1, all the row children will be expanded.", "density": "Set the density of the grid.", - "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows.", - "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows.", + "disableChildrenFiltering": "If true, the filtering will only be applied to the top level rows when grouping rows with the treeData prop.", + "disableChildrenSorting": "If true, the sorting will only be applied to the top level rows when grouping rows with the treeData prop.", "disableColumnFilter": "If true, column filters are disabled.", "disableColumnMenu": "If true, the column menu is disabled.", "disableColumnPinning": "If true, the column pinning is disabled.", @@ -27,6 +27,7 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", + "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", @@ -35,6 +36,7 @@ "editMode": "Controls whether to use the cell or row editing.", "editRowsModel": "Set the edit rows model of the grid.", "error": "An error that will turn the grid into its error state and display the error component.", + "experimentalFeatures": "Features under development. For each feature, if the flag is not explicitly set to true, the feature will be fully disabled and any property / method call will not have any effect.", "filterMode": "Filtering can be processed on the server or client-side. Set it to 'server' if you would like to handle filtering on the server-side.", "filterModel": "Set the filter model of the grid.", "getCellClassName": "Function that applies CSS classes dynamically on cells.

Signature:
function(params: GridCellParams) => string
params: With all properties from GridCellParams.
returns (string): The CSS class to apply to the cell.", @@ -42,6 +44,8 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -76,6 +80,7 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", + "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -445,6 +450,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/docs/translations/api-docs/data-grid/data-grid-pt.json b/docs/translations/api-docs/data-grid/data-grid-pt.json index e18a76c7e2635..d3be2f4ce0b35 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pt.json @@ -424,6 +424,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/docs/translations/api-docs/data-grid/data-grid-zh.json b/docs/translations/api-docs/data-grid/data-grid-zh.json index e18a76c7e2635..d3be2f4ce0b35 100644 --- a/docs/translations/api-docs/data-grid/data-grid-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-zh.json @@ -424,6 +424,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/docs/translations/api-docs/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid.json index e18a76c7e2635..d3be2f4ce0b35 100644 --- a/docs/translations/api-docs/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid.json @@ -424,6 +424,8 @@ "ExportIcon": "Icon displayed on the open export button present in the toolbar by default.", "MoreActionsIcon": "Icon displayed on the actions column type to open the menu.", "TreeDataExpandIcon": "Icon displayed on the tree data toggling column when the children are collapsed", - "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded" + "TreeDataCollapseIcon": "Icon displayed on the tree data toggling column when the children are expanded", + "GroupingCriteriaExpandIcon": "Icon displayed on the grouping column when the children are collapsed", + "GroupingCriteriaCollapseIcon": "Icon displayed on the grouping column when the children are expanded" } } diff --git a/packages/grid/_modules_/grid/GridComponentProps.ts b/packages/grid/_modules_/grid/GridComponentProps.ts index 616a917541d31..bc9fb24198c08 100644 --- a/packages/grid/_modules_/grid/GridComponentProps.ts +++ b/packages/grid/_modules_/grid/GridComponentProps.ts @@ -12,6 +12,7 @@ import { GridSimpleOptions, GridProcessedMergedOptions, GridMergedOptions, + GridExperimentalFeatures, } from './models/gridOptions'; import { GridRowIdGetter, GridRowModel, GridRowsProp } from './models/gridRows'; import { GridColumnTypesRecord } from './models/colDef/gridColumnTypesRecord'; @@ -26,6 +27,7 @@ import { GridClasses } from './gridClasses'; import { GridCallbackDetails } from './models/api/gridCallbackDetails'; import { GridPinnedColumns } from './models/api/gridColumnPinningApi'; import { GridEventListener, GridEvents } from './models/events'; +import type { GridGroupingColumnsModel } from './hooks/features/groupingColumns'; /** * The grid component react props before applying the default values. @@ -33,7 +35,13 @@ import { GridEventListener, GridEvents } from './models/events'; export interface GridInputComponentProps extends Partial, Partial, - GridComponentOtherProps {} + GridComponentOtherProps { + /** + * Features under development. + * For each feature, if the flag is not explicitly set to `true`, the feature will be fully disabled and any property / method call will not have any effect. + */ + experimentalFeatures?: { [key in GridExperimentalFeatures]?: boolean }; +} /** * The grid component react props after applying the default values. @@ -355,6 +363,19 @@ interface GridComponentOtherProps extends CommonProps { * @param {GridCallbackDetails} details Additional details for this callback. */ onSortModelChange?: (model: GridSortModel, details: GridCallbackDetails) => void; + /** + * Set the grouping columns of the grid. + */ + groupingColumnsModel?: GridGroupingColumnsModel; + /** + * Callback fired when the grouping columns model changes. + * @param {GridGroupingColumnsModel} model Columns used as grouping criteria. + * @param {GridCallbackDetails} details Additional details for this callback. + */ + onGroupingColumnsModelChange?: ( + model: GridGroupingColumnsModel, + details: GridCallbackDetails, + ) => void; /** * The column fields to display pinned to left or right. */ diff --git a/packages/grid/_modules_/grid/components/cell/GridBooleanCell.tsx b/packages/grid/_modules_/grid/components/cell/GridBooleanCell.tsx index 37a082df2ae36..c9b0c3407035e 100644 --- a/packages/grid/_modules_/grid/components/cell/GridBooleanCell.tsx +++ b/packages/grid/_modules_/grid/components/cell/GridBooleanCell.tsx @@ -18,7 +18,11 @@ const useUtilityClasses = (ownerState: OwnerState) => { return composeClasses(slots, getDataGridUtilityClass, classes); }; -export const GridBooleanCell = React.memo((props: GridRenderCellParams & SvgIconProps) => { +interface GridBooleanCellProps + extends GridRenderCellParams, + Omit {} + +export const GridBooleanCell = React.memo((props: GridBooleanCellProps) => { const { id, value, @@ -56,4 +60,10 @@ export const GridBooleanCell = React.memo((props: GridRenderCellParams & SvgIcon ); }); -export const renderBooleanCell = (params) => ; +export const renderBooleanCell = (params: GridBooleanCellProps) => { + if (params.rowNode.isAutoGenerated) { + return ''; + } + + return ; +}; diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx new file mode 100644 index 0000000000000..efedcebdad075 --- /dev/null +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import Box from '@mui/material/Box'; +import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; +import { GridRenderCellParams } from '../../models/params/gridCellParams'; + +const GridGroupingColumnLeafCell = (props: GridRenderCellParams) => { + const { rowNode } = props; + + const rootProps = useGridRootProps(); + + const marginLeft = rootProps.groupingColumnMode === 'multiple' ? 1 : rowNode.depth * 2; + + return {props.formattedValue ?? props.value}; +}; + +export { GridGroupingColumnLeafCell }; diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx new file mode 100644 index 0000000000000..00ce3e18bb7a4 --- /dev/null +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx @@ -0,0 +1,164 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { unstable_composeClasses as composeClasses } from '@mui/base'; +import IconButton from '@mui/material/IconButton'; +import Box from '@mui/material/Box'; +import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; +import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; +import { GridRenderCellParams } from '../../models/params/gridCellParams'; +import { useGridSelector } from '../../hooks/utils/useGridSelector'; +import { gridFilteredDescendantCountLookupSelector } from '../../hooks/features/filter/gridFilterSelector'; +import { isNavigationKey } from '../../utils/keyboardUtils'; +import { GridEvents } from '../../models/events'; +import { getDataGridUtilityClass } from '../../gridClasses'; +import { GridComponentProps } from '../../GridComponentProps'; + +type OwnerState = { classes: GridComponentProps['classes'] }; + +const useUtilityClasses = (ownerState: OwnerState) => { + const { classes } = ownerState; + + const slots = { + root: ['groupingCriteriaCell'], + toggle: ['groupingCriteriaCellToggle'], + }; + + return composeClasses(slots, getDataGridUtilityClass, classes); +}; + +interface GridGroupingCriteriaCellProps extends GridRenderCellParams { + hideDescendantCount?: boolean; +} + +const GridGroupingCriteriaCell = (props: GridGroupingCriteriaCellProps) => { + const { id, field, rowNode, hideDescendantCount } = props; + + const rootProps = useGridRootProps(); + const apiRef = useGridApiContext(); + const ownerState: OwnerState = { classes: rootProps.classes }; + const classes = useUtilityClasses(ownerState); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + + const Icon = rowNode.childrenExpanded + ? rootProps.components.GroupingCriteriaCollapseIcon + : rootProps.components.GroupingCriteriaExpandIcon; + + const handleKeyDown = (event) => { + if (event.key === ' ') { + event.stopPropagation(); + } + if (isNavigationKey(event.key) && !event.shiftKey) { + apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); + } + }; + + const handleClick = (event: React.MouseEvent) => { + apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); + apiRef.current.setCellFocus(id, field); + event.stopPropagation(); + }; + + const marginLeft = rootProps.groupingColumnMode === 'multiple' ? 0 : rowNode.depth * 2; + + return ( + +
+ {filteredDescendantCount > 0 && ( + + + + )} +
+ + {rowNode.groupingKey} + {!hideDescendantCount && filteredDescendantCount > 0 ? ` (${filteredDescendantCount})` : ''} + +
+ ); +}; + +GridGroupingCriteriaCell.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * GridApi that let you manipulate the grid. + */ + api: PropTypes.any.isRequired, + /** + * The mode of the cell. + */ + cellMode: PropTypes.oneOf(['edit', 'view']).isRequired, + /** + * The column of the row that the current cell belongs to. + */ + colDef: PropTypes.object.isRequired, + /** + * The column field of the cell that triggered the event. + */ + field: PropTypes.string.isRequired, + /** + * The cell value formatted with the column valueFormatter. + */ + formattedValue: PropTypes.oneOfType([ + PropTypes.instanceOf(Date), + PropTypes.number, + PropTypes.object, + PropTypes.string, + PropTypes.bool, + ]), + /** + * Get the cell value of a row and field. + * @param {GridRowId} id The row id. + * @param {string} field The field. + * @returns {GridCellValue} The cell value. + */ + getValue: PropTypes.func.isRequired, + /** + * If true, the cell is the active element. + */ + hasFocus: PropTypes.bool.isRequired, + /** + * The grid row id. + */ + id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + /** + * If true, the cell is editable. + */ + isEditable: PropTypes.bool, + /** + * The row model of the row that the current cell belongs to. + */ + row: PropTypes.object.isRequired, + /** + * the tabIndex value. + */ + tabIndex: PropTypes.oneOf([-1, 0]).isRequired, + /** + * The cell value, but if the column has valueGetter, use getValue. + */ + value: PropTypes.oneOfType([ + PropTypes.instanceOf(Date), + PropTypes.number, + PropTypes.object, + PropTypes.string, + PropTypes.bool, + ]), +} as any; + +export { GridGroupingCriteriaCell }; diff --git a/packages/grid/_modules_/grid/components/containers/GridRootStyles.ts b/packages/grid/_modules_/grid/components/containers/GridRootStyles.ts index a9a5a2907e6dc..3ca42fb02483d 100644 --- a/packages/grid/_modules_/grid/components/containers/GridRootStyles.ts +++ b/packages/grid/_modules_/grid/components/containers/GridRootStyles.ts @@ -302,6 +302,16 @@ export const GridRootStyles = styled('div', { alignSelf: 'stretch', marginRight: theme.spacing(2), }, + [`& .${gridClasses.groupingCriteriaCell}`]: { + display: 'flex', + alignItems: 'center', + width: '100%', + }, + [`& .${gridClasses.groupingCriteriaCellToggle}`]: { + flex: '0 0 28px', + alignSelf: 'stretch', + marginRight: theme.spacing(2), + }, }; return gridStyle; diff --git a/packages/grid/_modules_/grid/components/icons/index.tsx b/packages/grid/_modules_/grid/components/icons/index.tsx index 395644208d92c..4e4a83b7542b4 100644 --- a/packages/grid/_modules_/grid/components/icons/index.tsx +++ b/packages/grid/_modules_/grid/components/icons/index.tsx @@ -17,7 +17,7 @@ export const GridExpandMoreIcon = createSvgIcon( ); export const GridExpandLessIcon = createSvgIcon( - , + , 'ExpandMore', ); diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx new file mode 100644 index 0000000000000..3f47ffd9a242d --- /dev/null +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx @@ -0,0 +1,116 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import MenuItem from '@mui/material/MenuItem'; +import Divider from '@mui/material/Divider'; +import { useGridApiContext } from '../../../hooks/utils/useGridApiContext'; +import { GridColDef } from '../../../models/colDef/gridColDef'; +import { useGridSelector } from '../../../hooks/utils/useGridSelector'; +import { gridGroupingColumnsSanitizedModelSelector } from '../../../hooks/features/groupingColumns/gridGroupingColumnsSelector'; +import { + getGroupingCriteriaFieldFromGroupingColDefField, + GROUPING_COLUMN_SINGLE, + isGroupingColumn, +} from '../../../hooks/features/groupingColumns/gridGroupingColumnsUtils'; +import { gridColumnLookupSelector } from '../../../hooks/features/columns/gridColumnsSelector'; + +interface GridGroupingColumnsMenuItemsProps { + column?: GridColDef; + onClick?: (event: React.MouseEvent) => void; +} + +const GridGroupingColumnsMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { + const { column, onClick } = props; + const apiRef = useGridApiContext(); + const groupingColumnsModel = useGridSelector(apiRef, gridGroupingColumnsSanitizedModelSelector); + const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector); + + const isGrouped = React.useMemo( + () => column?.field && groupingColumnsModel.includes(column.field), + [column, groupingColumnsModel], + ); + + const renderGroupingMenuItem = (field: string) => { + const name = columnsLookup[field].headerName ?? field; + + const groupColumn = (event: React.MouseEvent) => { + apiRef.current.addGroupingCriteria(field); + if (onClick) { + onClick(event); + } + }; + + return ( + {apiRef.current.getLocaleText('groupColumn')(name)} + ); + }; + + const renderUnGroupingMenuItem = (field: string) => { + const ungroupColumn = (event: React.MouseEvent) => { + apiRef.current.removeGroupingCriteria(field); + if (onClick) { + onClick(event); + } + }; + + const name = columnsLookup[field].headerName ?? field; + + return ( + + {apiRef.current.getLocaleText('unGroupColumn')(name)} + + ); + }; + + if (!column) { + return null; + } + + if (isGroupingColumn(column.field)) { + if (column.field === GROUPING_COLUMN_SINGLE) { + return ( + + + {groupingColumnsModel.map(renderUnGroupingMenuItem)} + + ); + } + + return ( + + + {renderUnGroupingMenuItem(getGroupingCriteriaFieldFromGroupingColDefField(column.field)!)} + + ); + } + + if (isGrouped) { + return ( + + + {renderUnGroupingMenuItem(column.field)} + + ); + } + + if (!column.canBeGrouped) { + return null; + } + + return ( + + + {renderGroupingMenuItem(column.field)} + + ); +}; + +GridGroupingColumnsMenuItems.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + column: PropTypes.object, + onClick: PropTypes.func, +} as any; + +export { GridGroupingColumnsMenuItems }; diff --git a/packages/grid/_modules_/grid/constants/localeTextConstants.ts b/packages/grid/_modules_/grid/constants/localeTextConstants.ts index 7072a05194439..f41727b7785ac 100644 --- a/packages/grid/_modules_/grid/constants/localeTextConstants.ts +++ b/packages/grid/_modules_/grid/constants/localeTextConstants.ts @@ -115,6 +115,11 @@ export const GRID_DEFAULT_LOCALE_TEXT: GridLocaleText = { treeDataExpand: 'see children', treeDataCollapse: 'hide children', + // Grouping columns + groupingColumnHeaderName: 'Group', + groupColumn: (name) => `Group by ${name}`, + unGroupColumn: (name) => `Stop grouping by ${name}`, + // Used core components translation keys MuiTablePagination: {}, }; diff --git a/packages/grid/_modules_/grid/gridClasses.ts b/packages/grid/_modules_/grid/gridClasses.ts index e8568dae50656..b8f75ee95af15 100644 --- a/packages/grid/_modules_/grid/gridClasses.ts +++ b/packages/grid/_modules_/grid/gridClasses.ts @@ -382,4 +382,6 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'withBorder', 'treeDataGroupingCell', 'treeDataGroupingCellToggle', + 'groupingCriteriaCell', + 'groupingCriteriaCellToggle', ]); diff --git a/packages/grid/_modules_/grid/hooks/features/filter/gridFilterState.ts b/packages/grid/_modules_/grid/hooks/features/filter/gridFilterState.ts index 2963cba9ed1b1..036a164c501ac 100644 --- a/packages/grid/_modules_/grid/hooks/features/filter/gridFilterState.ts +++ b/packages/grid/_modules_/grid/hooks/features/filter/gridFilterState.ts @@ -1,4 +1,4 @@ -import { GridLinkOperator } from '../../../models/gridFilterItem'; +import { GridFilterItem, GridLinkOperator } from '../../../models/gridFilterItem'; import { GridFilterModel } from '../../../models/gridFilterModel'; import { GridRowId } from '../../../models/gridRows'; @@ -30,8 +30,17 @@ export interface GridFilterInitialState { filterModel?: GridFilterModel; } +/** + * @param {GridRowId} rowId The id of the row we want to filter. + * @param {(filterItem: GridFilterItem) => boolean} shouldApplyItem An optional callback to allow the filtering engine to only apply some items. + */ +export type GridAggregatedFilterItemApplier = ( + rowId: GridRowId, + shouldApplyItem?: (filterItem: GridFilterItem) => boolean, +) => boolean; + export interface GridFilteringParams { - isRowMatchingFilters: ((rowId: GridRowId) => boolean) | null; + isRowMatchingFilters: GridAggregatedFilterItemApplier | null; } export type GridFilteringMethod = ( diff --git a/packages/grid/_modules_/grid/hooks/features/filter/useGridFilter.ts b/packages/grid/_modules_/grid/hooks/features/filter/useGridFilter.ts index 56508e1211143..f61f861a53c4d 100644 --- a/packages/grid/_modules_/grid/hooks/features/filter/useGridFilter.ts +++ b/packages/grid/_modules_/grid/hooks/features/filter/useGridFilter.ts @@ -16,6 +16,7 @@ import { getDefaultGridFilterModel, GridFilteringMethod, GridFilteringMethodCollection, + GridAggregatedFilterItemApplier, } from './gridFilterState'; import { GridFilterModel } from '../../../models/gridFilterModel'; import { gridFilterModelSelector, gridVisibleSortedRowEntriesSelector } from './gridFilterSelector'; @@ -25,7 +26,10 @@ import { gridRowIdsSelector, gridRowGroupingNameSelector } from '../rows'; import { GridPreProcessingGroup } from '../../core/preProcessing'; import { useGridRegisterFilteringMethod } from './useGridRegisterFilteringMethod'; -type GridFilterItemApplier = (rowId: GridRowId) => boolean; +type GridFilterItemApplier = { + fn: (rowId: GridRowId) => boolean; + item: GridFilterItem; +}; const checkFilterModelValidity = (model: GridFilterModel) => { if (model.items.length > 1) { @@ -88,7 +92,7 @@ export const useGridFilter = ( }); const buildAggregatedFilterApplier = React.useCallback( - (filterModel: GridFilterModel): GridFilterItemApplier | null => { + (filterModel: GridFilterModel): GridAggregatedFilterItemApplier | null => { const { items, linkOperator = GridLinkOperator.And } = filterModel; const getFilterCallbackFromItem = ( @@ -127,11 +131,16 @@ export const useGridFilter = ( return null; } - return (rowId: GridRowId) => { + const fn = (rowId: GridRowId) => { const cellParams = apiRef.current.getCellParams(rowId, newFilterItem.columnField!); return applyFilterOnRow(cellParams); }; + + return { + fn, + item: newFilterItem, + }; }; const appliers = items @@ -142,14 +151,18 @@ export const useGridFilter = ( return null; } - return (rowId: GridRowId) => { + return (rowId, shouldApplyFilter) => { + const filteredAppliers = shouldApplyFilter + ? appliers.filter((applier) => shouldApplyFilter(applier.item)) + : appliers; + // Return `false` as soon as we have a failing filter if (linkOperator === GridLinkOperator.And) { - return appliers.every((applier) => applier(rowId)); + return filteredAppliers.every((applier) => applier.fn(rowId)); } // Return `true` as soon as we have a passing filter - return appliers.some((applier) => applier(rowId)); + return filteredAppliers.some((applier) => applier.fn(rowId)); }; }, [apiRef], diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx b/packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx new file mode 100644 index 0000000000000..d18162e6fad85 --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx @@ -0,0 +1,360 @@ +import * as React from 'react'; +import { + GRID_STRING_COL_DEF, + GridApiRef, + GridColDef, + GridGroupingColDefOverride, + GridRenderCellParams, + GridStateColDef, + GridValueGetterFullParams, + GridComparatorFn, +} from '../../../models'; +import { GridColumnRawLookup } from '../columns/gridColumnsState'; +import { GridGroupingCriteriaCell } from '../../../components/cell/GridGroupingCriteriaCell'; +import { GridGroupingColumnLeafCell } from '../../../components/cell/GridGroupingColumnLeafCell'; +import { getGroupingColDefFieldFromGroupingCriteriaField } from './gridGroupingColumnsUtils'; +import { gridGroupingColumnsSanitizedModelSelector } from './gridGroupingColumnsSelector'; + +const GROUPING_COL_DEF_DEFAULT_PROPERTIES: Omit = { + ...GRID_STRING_COL_DEF, + disableReorder: true, +}; + +const GROUPING_COL_DEF_FORCED_PROPERTIES: Pick = { + type: 'rowGroupByColumnsGroup', + editable: false, + canBeGrouped: false, +}; + +/** + * When sorting two cells with different grouping criteria, we consider that the cell with the grouping criteria coming first in the model should be displayed below. + * This can occur when some rows don't have all the fields. In which case we want the rows with the missing field to be displayed above. + * TODO: Make this index comparator depth invariant, the logic should not be inverted when sorting in the "desc" direction (but the current return format of `sortComparator` does not support this behavior). + */ +const groupingFieldIndexComparator: GridComparatorFn = (v1, v2, cellParams1, cellParams2) => { + const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(cellParams1.api.state); + const groupingField1 = cellParams1.rowNode.groupingField; + const groupingField2 = cellParams2.rowNode.groupingField; + + if (groupingField1 === groupingField2) { + return 0; + } + + if (groupingField1 == null) { + return -1; + } + + if (groupingField2 == null) { + return 1; + } + + if (groupingColumnsModel.indexOf(groupingField1) < groupingColumnsModel.indexOf(groupingField2)) { + return -1; + } + + return 1; +}; + +const getLeafProperties = (leafColDef: GridColDef): Partial => ({ + headerName: leafColDef.headerName ?? leafColDef.field, + sortable: leafColDef.sortable, + filterable: leafColDef.filterable, + filterOperators: leafColDef.filterOperators?.map((operator) => ({ + ...operator, + getApplyFilterFn: (filterItem, column) => { + const originalFn = operator.getApplyFilterFn(filterItem, column); + if (!originalFn) { + return null; + } + + return (params) => { + // We only want to filter leaves + if (params.rowNode.groupingField != null) { + return true; + } + + return originalFn(params); + }; + }, + })), + sortComparator: (v1, v2, cellParams1, cellParams2) => { + // We only want to sort the leaves + if (cellParams1.rowNode.groupingField === null && cellParams2.rowNode.groupingField === null) { + return leafColDef.sortComparator!(v1, v2, cellParams1, cellParams2); + } + + return groupingFieldIndexComparator(v1, v2, cellParams1, cellParams2); + }, +}); + +const getGroupingCriteriaProperties = (groupedByColDef: GridColDef, applyHeaderName: boolean) => { + const properties: Partial = { + sortable: groupedByColDef.sortable, + filterable: groupedByColDef.filterable, + sortComparator: (v1, v2, cellParams1, cellParams2) => { + // We only want to sort the groups of the current grouping criteria + if ( + cellParams1.rowNode.groupingField === groupedByColDef.field && + cellParams2.rowNode.groupingField === groupedByColDef.field + ) { + return groupedByColDef.sortComparator!(v1, v2, cellParams1, cellParams2); + } + + return groupingFieldIndexComparator(v1, v2, cellParams1, cellParams2); + }, + filterOperators: groupedByColDef.filterOperators?.map((operator) => ({ + ...operator, + getApplyFilterFn: (filterItem, column) => { + const originalFn = operator.getApplyFilterFn(filterItem, column); + if (!originalFn) { + return null; + } + + return (params) => { + // We only want to filter the groups of the current grouping criteria + if (params.rowNode.groupingField !== groupedByColDef.field) { + return true; + } + + return originalFn(params); + }; + }, + })), + }; + + if (applyHeaderName) { + properties.headerName = groupedByColDef.headerName ?? groupedByColDef.field; + } + + return properties; +}; + +interface CreateGroupingColDefMonoCriteriaParams { + columnsLookup: GridColumnRawLookup; + + /** + * The field from which we are grouping the rows. + */ + groupingCriteria: string; + + /** + * The col def from which we are grouping the rows. + */ + groupedByColDef: GridColDef | GridStateColDef; + + /** + * The col def properties the user wants to override. + * This value comes `prop.groupingColDef`. + */ + colDefOverride: GridGroupingColDefOverride | null | undefined; +} + +/** + * Creates the `GridColDef` for a grouping column that only takes care of a single grouping criteria + */ +export const createGroupingColDefForOneGroupingCriteria = ({ + columnsLookup, + groupedByColDef, + groupingCriteria, + colDefOverride, +}: CreateGroupingColDefMonoCriteriaParams): GridColDef => { + const { leafField, mainGroupingCriteria, hideDescendantCount, ...colDefOverrideProperties } = + colDefOverride ?? {}; + const leafColDef = leafField ? columnsLookup[leafField] : null; + + // The properties that do not depend on the presence of a `leafColDef` and that can be overridden by `colDefOverride` + const commonProperties: Partial = { + width: Math.max( + (groupedByColDef.width ?? GRID_STRING_COL_DEF.width!) + 40, + leafColDef?.width ?? 0, + ), + renderCell: (params: GridRenderCellParams) => { + // Render leaves + if (params.rowNode.groupingField == null) { + if (leafColDef) { + const leafParams: GridRenderCellParams = { + ...params.api.getCellParams(params.id, leafField!), + api: params.api, + }; + if (leafColDef.renderCell) { + return leafColDef.renderCell(leafParams); + } + + return ; + } + + return null; + } + + // Render current grouping criteria groups + if (params.rowNode.groupingField === groupingCriteria) { + return ; + } + + return null; + }, + valueGetter: (params) => { + const fullParams = params as GridValueGetterFullParams; + if (!fullParams.rowNode) { + return undefined; + } + + if (fullParams.rowNode.groupingField == null) { + if (leafColDef) { + return fullParams.api.getCellValue(params.id, leafField!); + } + + return undefined; + } + + if (fullParams.rowNode.groupingField === groupingCriteria) { + return fullParams.rowNode.groupingKey; + } + + return undefined; + }, + }; + + // If we have a `mainGroupingCriteria` defined and matching the `groupingCriteria` + // Then we apply the sorting / filtering on the groups of this column's grouping criteria based on the properties of `groupedByColDef`. + // It can be useful to define a `leafField` for leaves rendering but still use the grouping criteria for the sorting / filtering + // + // If we have a `leafField` defined and matching an existing column + // Then we apply the sorting / filtering on the leaves based on the properties of `leavesColDef` + // + // By default, we apply the sorting / filtering on the groups of this column's grouping criteria based on the properties of `groupedColDef`. + let sourceProperties: Partial; + if (mainGroupingCriteria && mainGroupingCriteria === groupingCriteria) { + sourceProperties = getGroupingCriteriaProperties(groupedByColDef, true); + } else if (leafColDef) { + sourceProperties = getLeafProperties(leafColDef); + } else { + sourceProperties = getGroupingCriteriaProperties(groupedByColDef, true); + } + + // The properties that can't be overridden with `colDefOverride` + const forcedProperties: Pick = { + field: getGroupingColDefFieldFromGroupingCriteriaField(groupingCriteria), + ...GROUPING_COL_DEF_FORCED_PROPERTIES, + }; + + return { + ...GROUPING_COL_DEF_DEFAULT_PROPERTIES, + ...commonProperties, + ...sourceProperties, + ...colDefOverrideProperties, + ...forcedProperties, + }; +}; + +interface CreateGroupingColDefSeveralCriteriaParams { + apiRef: GridApiRef; + columnsLookup: GridColumnRawLookup; + + /** + * The fields from which we are grouping the rows. + */ + groupingColumnsModel: string[]; + + /** + * The col def properties the user wants to override. + * This value comes `prop.groupingColDef`. + */ + colDefOverride: GridGroupingColDefOverride | null | undefined; +} + +/** + * Creates the `GridColDef` for a grouping column that takes care of all the grouping criteria + */ +export const createGroupingColDefForAllGroupingCriteria = ({ + apiRef, + columnsLookup, + groupingColumnsModel, + colDefOverride, +}: CreateGroupingColDefSeveralCriteriaParams): GridColDef => { + const { leafField, mainGroupingCriteria, hideDescendantCount, ...colDefOverrideProperties } = + colDefOverride ?? {}; + const leafColDef = leafField ? columnsLookup[leafField] : null; + + // The properties that do not depend on the presence of a `leafColDef` and that can be overridden by `colDefOverride` + const commonProperties: Partial = { + headerName: apiRef.current.getLocaleText('groupingColumnHeaderName'), + width: Math.max( + ...groupingColumnsModel.map( + (field) => (columnsLookup[field].width ?? GRID_STRING_COL_DEF.width!) + 40, + ), + leafColDef?.width ?? 0, + ), + renderCell: (params) => { + // Render the leaves + if (params.rowNode.groupingField == null) { + if (leafColDef) { + const leafParams: GridRenderCellParams = { + ...params.api.getCellParams(params.id, leafField!), + api: params.api, + }; + if (leafColDef.renderCell) { + return leafColDef.renderCell(leafParams); + } + + return ; + } + + return null; + } + + // Render the groups + return ; + }, + valueGetter: (params) => { + const fullParams = params as GridValueGetterFullParams; + if (!fullParams.rowNode) { + return undefined; + } + + if (fullParams.rowNode.groupingField == null) { + if (leafColDef) { + return fullParams.api.getCellValue(params.id, leafField!); + } + + return undefined; + } + + return fullParams.rowNode.groupingKey; + }, + }; + + // If we have a `mainGroupingCriteria` defined and matching one of the `orderedGroupedByFields` + // Then we apply the sorting / filtering on the groups of this column's grouping criteria based on the properties of `columnsLookup[mainGroupingCriteria]`. + // It can be useful to use another grouping criteria than the top level one for the sorting / filtering + // + // If we have a `leafField` defined and matching an existing column + // Then we apply the sorting / filtering on the leaves based on the properties of `leavesColDef` + // + // By default, we apply the sorting / filtering on the groups of the top level grouping criteria based on the properties of `columnsLookup[orderedGroupedByFields[0]]`. + let sourceProperties: Partial; + if (mainGroupingCriteria && groupingColumnsModel.includes(mainGroupingCriteria)) { + sourceProperties = getGroupingCriteriaProperties(columnsLookup[mainGroupingCriteria], true); + } else if (leafColDef) { + sourceProperties = getLeafProperties(leafColDef); + } else { + sourceProperties = getGroupingCriteriaProperties( + columnsLookup[groupingColumnsModel[0]], + groupingColumnsModel.length === 1, + ); + } + + // The properties that can't be overridden with `colDefOverride` + const forcedProperties: Pick = { + field: getGroupingColDefFieldFromGroupingCriteriaField(null), + ...GROUPING_COL_DEF_FORCED_PROPERTIES, + }; + + return { + ...GROUPING_COL_DEF_DEFAULT_PROPERTIES, + ...commonProperties, + ...sourceProperties, + ...colDefOverrideProperties, + ...forcedProperties, + }; +}; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts new file mode 100644 index 0000000000000..19e550dccd0a6 --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts @@ -0,0 +1,37 @@ +export type GridGroupingColumnsModel = string[]; + +export interface GridGroupingColumnsState { + model: GridGroupingColumnsModel; +} + +export interface GridGroupingColumnsInitialState { + model?: GridGroupingColumnsModel; +} + +export interface GridGroupingColumnsApi { + /** + * Sets the columns to use as grouping criteria. + * @param {GridGroupingColumnsModel} model The columns to use as grouping criteria. + */ + setGroupingColumnsModel: (model: GridGroupingColumnsModel) => void; + + /** + * Add the field to the groupingColumnsModel. + * @param {string} groupingCriteriaField The field from which we want to group the rows. + * @param {number | undefined} groupingIndex The grouping index at which we want to insert the new grouping criteria. By default, it will be inserted at the end of the model. + */ + addGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => void; + + /** + * Remove the field from to groupingColumnsModel. + * @param {string} groupingCriteriaField The field from which we want to stop grouping the rows. + */ + removeGroupingCriteria: (groupingCriteriaField: string) => void; + + /** + * Sets the grouping index of a grouping criteria. + * @param {string} groupingCriteriaField The field of the grouping criteria from which we want to change the grouping index. + * @param {number} groupingIndex The new grouping index of this grouping criteria. + */ + setGroupingCriteriaIndex: (groupingCriteriaField: string, groupingIndex: number) => void; +} diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts new file mode 100644 index 0000000000000..7793d7a35b6fb --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts @@ -0,0 +1,17 @@ +import { createSelector } from 'reselect'; +import { GridState } from '../../../models'; +import { gridColumnLookupSelector } from '../columns'; + +export const gridGroupingColumnsStateSelector = (state: GridState) => state.groupingColumns; + +export const gridGroupingColumnsModelSelector = createSelector( + gridGroupingColumnsStateSelector, + (groupingColumns) => groupingColumns.model, +); + +export const gridGroupingColumnsSanitizedModelSelector = createSelector( + gridGroupingColumnsModelSelector, + gridColumnLookupSelector, + (model, columnsLookup) => + model.filter((field) => !!columnsLookup[field] && columnsLookup[field].canBeGrouped), +); diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts new file mode 100644 index 0000000000000..ad1a6a13a5e4a --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts @@ -0,0 +1,147 @@ +import { + GridFilterItem, + GridRowId, + GridRowTreeConfig, + GridRowTreeNodeConfig, +} from '../../../models'; +import { GridFilterState } from '../filter'; +import { GridComponentProps } from '../../../GridComponentProps'; +import { GridAggregatedFilterItemApplier } from '../filter/gridFilterState'; + +export const GROUPING_COLUMN_SINGLE = '__row_group_by_columns_group__'; + +export const GROUPING_COLUMNS_FEATURE_NAME = 'grouping-columns'; + +export const getGroupingColDefFieldFromGroupingCriteriaField = ( + groupingCriteria: string | null, +) => { + if (groupingCriteria === null) { + return GROUPING_COLUMN_SINGLE; + } + + return `__row_group_by_columns_group_${groupingCriteria}__`; +}; + +export const getGroupingCriteriaFieldFromGroupingColDefField = (groupingColDefField: string) => { + const match = groupingColDefField.match(/^__row_group_by_columns_group_(.*)__$/); + + if (!match) { + return null; + } + + return match[1]; +}; + +export const isGroupingColumn = (field: string) => + field === GROUPING_COLUMN_SINGLE || + getGroupingCriteriaFieldFromGroupingColDefField(field) !== null; + +interface FilterRowTreeFromTreeDataParams { + rowTree: GridRowTreeConfig; + isRowMatchingFilters: GridAggregatedFilterItemApplier | null; +} + +/** + * When filtering a group, we only want to filter according to the items related to this grouping column. + */ +const shouldApplyFilterItemOnGroup = (item: GridFilterItem, node: GridRowTreeNodeConfig) => { + if (item.columnField === GROUPING_COLUMN_SINGLE) { + return true; + } + + const groupingCriteriaField = getGroupingCriteriaFieldFromGroupingColDefField(item.columnField); + + return groupingCriteriaField === node.groupingField; +}; + +/** + * A leaf is visible if it passed the filter + * A group is visible if all the following criteria are met: + * - One of its children is passing the filter + * - It is passing the filter + */ +export const filterRowTreeFromGroupingColumns = ( + params: FilterRowTreeFromTreeDataParams, +): Pick => { + const { rowTree, isRowMatchingFilters } = params; + const visibleRowsLookup: Record = {}; + const filteredDescendantCountLookup: Record = {}; + + const filterTreeNode = ( + node: GridRowTreeNodeConfig, + areAncestorsPassingChildren: boolean, + areAncestorsExpanded: boolean, + ): number => { + let isMatchingFilters: boolean; + if (!isRowMatchingFilters) { + isMatchingFilters = true; + } else { + const shouldApplyItem = node.isAutoGenerated + ? (item: GridFilterItem) => shouldApplyFilterItemOnGroup(item, node) + : undefined; + + isMatchingFilters = isRowMatchingFilters(node.id, shouldApplyItem); + } + + let filteredDescendantCount = 0; + node.children?.forEach((childId) => { + const childNode = rowTree[childId]; + const childSubTreeSize = filterTreeNode( + childNode, + areAncestorsPassingChildren && isMatchingFilters, + areAncestorsExpanded && !!node.childrenExpanded, + ); + filteredDescendantCount += childSubTreeSize; + }); + + let shouldPassFilters: boolean; + if (!areAncestorsPassingChildren) { + shouldPassFilters = false; + } else if (node.children?.length) { + shouldPassFilters = isMatchingFilters && filteredDescendantCount > 0; + } else { + shouldPassFilters = isMatchingFilters; + } + + visibleRowsLookup[node.id] = shouldPassFilters && areAncestorsExpanded; + + if (!shouldPassFilters) { + return 0; + } + + filteredDescendantCountLookup[node.id] = filteredDescendantCount; + + if (!node.children) { + return filteredDescendantCount + 1; + } + + return filteredDescendantCount; + }; + + const nodes = Object.values(rowTree); + for (let i = 0; i < nodes.length; i += 1) { + const node = nodes[i]; + if (node.depth === 0) { + filterTreeNode(node, true, true); + } + } + + return { + visibleRowsLookup, + filteredDescendantCountLookup, + }; +}; + +export const getColDefOverrides = ( + propGroupingColDef: GridComponentProps['groupingColDef'], + fields: string[], +) => { + if (typeof propGroupingColDef === 'function') { + return propGroupingColDef({ + groupingName: GROUPING_COLUMNS_FEATURE_NAME, + fields, + }); + } + + return propGroupingColDef; +}; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts new file mode 100644 index 0000000000000..52b8bf7b17a6a --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts @@ -0,0 +1,2 @@ +export * from './gridGroupingColumnsSelector'; +export * from './gridGroupingColumnsInterfaces'; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx b/packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx new file mode 100644 index 0000000000000..90e85d769318a --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx @@ -0,0 +1,483 @@ +import * as React from 'react'; +import type { + GridApiRef, + GridRowModel, + GridRowId, + GridColDef, + GridKeyValue, + GridCellValue, + GridValueGetterSimpleParams, +} from '../../../models'; +import { GridEvents, GridEventListener } from '../../../models/events'; +import { GridRowGroupingPreProcessing } from '../../core/rowGroupsPerProcessing'; +import { useFirstRender } from '../../utils/useFirstRender'; +import { buildRowTree, BuildRowTreeGroupingCriteria } from '../../../utils/tree/buildRowTree'; +import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; +import { + gridGroupingColumnsModelSelector, + gridGroupingColumnsSanitizedModelSelector, +} from './gridGroupingColumnsSelector'; +import { GridComponentProps } from '../../../GridComponentProps'; +import { + filterRowTreeFromGroupingColumns, + getGroupingColDefFieldFromGroupingCriteriaField, + getColDefOverrides, + GROUPING_COLUMNS_FEATURE_NAME, + isGroupingColumn, +} from './gridGroupingColumnsUtils'; +import { + createGroupingColDefForOneGroupingCriteria, + createGroupingColDefForAllGroupingCriteria, +} from './createGroupingColDef'; +import { isDeepEqual } from '../../../utils/utils'; +import { GridPreProcessingGroup, useGridRegisterPreProcessor } from '../../core/preProcessing'; +import { GridColumnsRawState } from '../columns/gridColumnsState'; +import { useGridRegisterFilteringMethod } from '../filter/useGridRegisterFilteringMethod'; +import { GridFilteringMethod } from '../filter/gridFilterState'; +import { gridRowIdsSelector, gridRowTreeSelector } from '../rows'; +import { useGridRegisterSortingMethod } from '../sorting/useGridRegisterSortingMethod'; +import { GridSortingMethod } from '../sorting/gridSortingState'; +import { sortRowTree } from '../../../utils/tree/sortRowTree'; +import { gridFilteredDescendantCountLookupSelector } from '../filter'; +import { useGridStateInit } from '../../utils/useGridStateInit'; +import { GridGroupingColumnsApi, GridGroupingColumnsModel } from './gridGroupingColumnsInterfaces'; +import { useGridApiMethod, useGridState } from '../../utils'; +import { gridColumnLookupSelector } from '../columns'; +import { GridGroupingColumnsMenuItems } from '../../../components/menu/columnMenu/GridGroupingColumnsMenuItems'; + +/** + * Only available in DataGridPro + * @requires useGridColumns (state, method) - can be after, async only + * @requires useGridRows (state, method) - can be after, async only + * @requires useGridParamsApi (method) - can be after, async only + * TODO: Move the the Premium plan once available and remove the `experimentalFeatures.groupingColumns` flag + */ +export const useGridGroupingColumns = ( + apiRef: GridApiRef, + props: Pick< + GridComponentProps, + | 'initialState' + | 'groupingColumnsModel' + | 'onGroupingColumnsModelChange' + | 'defaultGroupingExpansionDepth' + | 'groupingColDef' + | 'groupingColumnMode' + | 'disableGroupingColumns' + >, +) => { + useGridStateInit(apiRef, (state) => ({ + ...state, + groupingColumns: { + model: props.groupingColumnsModel ?? props.initialState?.groupingColumns?.model ?? [], + }, + })); + + const [, setGridState, forceUpdate] = useGridState(apiRef); + + apiRef.current.unstable_updateControlState({ + stateId: 'groupingColumns', + propModel: props.groupingColumnsModel, + propOnChange: props.onGroupingColumnsModelChange, + stateSelector: gridGroupingColumnsModelSelector, + changeEvent: GridEvents.groupingColumnsModelChange, + }); + + /** + * ROW GROUPING + */ + // Tracks the model on the last pre-processing to check if we need to re-build the grouping columns when the grid upserts a column. + const sanitizedModelOnLastRowPreProcessing = React.useRef([]); + + const updateRowGrouping = React.useCallback(() => { + const groupRows: GridRowGroupingPreProcessing = (params) => { + const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(apiRef.current.state); + const columnsLookup = gridColumnLookupSelector(apiRef.current.state); + sanitizedModelOnLastRowPreProcessing.current = groupingColumnsModel; + + if (props.disableGroupingColumns || groupingColumnsModel.length === 0) { + return null; + } + + const distinctValues: { + [field: string]: { lookup: { [val: string]: boolean }; list: any[] }; + } = Object.fromEntries( + groupingColumnsModel.map((groupingField) => [groupingField, { lookup: {}, list: [] }]), + ); + + const getCellGroupingCriteria = ({ + row, + id, + colDef, + }: { + row: GridRowModel; + id: GridRowId; + colDef: GridColDef; + }) => { + let value: GridCellValue; + if (colDef.valueGetter) { + const valueGetterParams: GridValueGetterSimpleParams = { + colDef, + field: colDef.field, + id, + row, + rowNode: { + isAutoGenerated: false, + id, + }, + }; + value = colDef.valueGetter(valueGetterParams); + } else { + value = row[colDef.field]; + } + + let key: GridKeyValue | null | undefined; + if (colDef.keyGetter) { + key = colDef.keyGetter({ + value, + id, + field: colDef.field, + }); + } else { + key = value as GridKeyValue; + } + + return { + key, + field: colDef.field, + }; + }; + + params.ids.forEach((rowId) => { + const row = params.idRowsLookup[rowId]; + + groupingColumnsModel.forEach((groupingCriteria) => { + const { key } = getCellGroupingCriteria({ + row, + id: rowId, + colDef: columnsLookup[groupingCriteria], + }); + const groupingFieldsDistinctKeys = distinctValues[groupingCriteria]; + + if (key != null && !groupingFieldsDistinctKeys.lookup[key.toString()]) { + groupingFieldsDistinctKeys.lookup[key.toString()] = true; + groupingFieldsDistinctKeys.list.push(key); + } + }); + }); + + const rows = params.ids.map((rowId) => { + const row = params.idRowsLookup[rowId]; + const parentPath = groupingColumnsModel + .map((groupingField) => + getCellGroupingCriteria({ + row, + id: rowId, + colDef: columnsLookup[groupingField], + }), + ) + .filter((cell) => cell.key != null) as BuildRowTreeGroupingCriteria[]; + + const leafGroupingCriteria: BuildRowTreeGroupingCriteria = { + key: rowId.toString(), + field: null, + }; + + return { + path: [...parentPath, leafGroupingCriteria], + id: rowId, + }; + }); + + return buildRowTree({ + ...params, + rows, + defaultGroupingExpansionDepth: props.defaultGroupingExpansionDepth, + groupingName: GROUPING_COLUMNS_FEATURE_NAME, + }); + }; + + return apiRef.current.unstable_registerRowGroupsBuilder('rowGrouping', groupRows); + }, [apiRef, props.defaultGroupingExpansionDepth, props.disableGroupingColumns]); + + useFirstRender(() => { + updateRowGrouping(); + }); + + const isFirstRender = React.useRef(true); + React.useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + return; + } + + updateRowGrouping(); + }, [updateRowGrouping]); + + /** + * PRE-PROCESSING + */ + const getGroupingColDefs = React.useCallback( + (columnsState: GridColumnsRawState) => { + if (props.disableGroupingColumns) { + return []; + } + + const propGroupingColDef = props.groupingColDef; + + // We can't use `gridGroupingRowsSanitizedModelSelector` here because the new columns are not in the state yet + const groupingColumnsModel = gridGroupingColumnsModelSelector(apiRef.current.state).filter( + (field) => !!columnsState.lookup[field], + ); + + if (groupingColumnsModel.length === 0) { + return []; + } + + switch (props.groupingColumnMode) { + case 'single': { + return [ + createGroupingColDefForAllGroupingCriteria({ + apiRef, + groupingColumnsModel, + colDefOverride: getColDefOverrides(propGroupingColDef, groupingColumnsModel), + columnsLookup: columnsState.lookup, + }), + ]; + } + + case 'multiple': { + return groupingColumnsModel.map((groupingCriteria) => + createGroupingColDefForOneGroupingCriteria({ + groupingCriteria, + colDefOverride: getColDefOverrides(propGroupingColDef, [groupingCriteria]), + groupedByColDef: columnsState.lookup[groupingCriteria], + columnsLookup: columnsState.lookup, + }), + ); + } + + default: { + return []; + } + } + }, + [apiRef, props.groupingColDef, props.groupingColumnMode, props.disableGroupingColumns], + ); + + const updateGroupingColumn = React.useCallback( + (columnsState: GridColumnsRawState) => { + const groupingColDefs = getGroupingColDefs(columnsState); + + // We remove the grouping columns + const newColumnFields: string[] = []; + columnsState.all.forEach((field) => { + if (isGroupingColumn(field)) { + delete columnsState.lookup[field]; + } else { + newColumnFields.push(field); + } + }); + columnsState.all = newColumnFields; + + // We add the grouping column + groupingColDefs.forEach((groupingColDef) => { + columnsState.lookup[groupingColDef.field] = groupingColDef; + }); + const startIndex = columnsState.all[0] === '__check__' ? 1 : 0; + columnsState.all = [ + ...columnsState.all.slice(0, startIndex), + ...groupingColDefs.map((colDef) => colDef.field), + ...columnsState.all.slice(startIndex), + ]; + + return columnsState; + }, + [getGroupingColDefs], + ); + + const addColumnMenuButtons = React.useCallback( + (initialValue: JSX.Element[]) => { + if (props.disableGroupingColumns) { + return initialValue; + } + + return [...initialValue, ]; + }, + [props.disableGroupingColumns], + ); + + const filteringMethod = React.useCallback( + (params) => { + const rowTree = gridRowTreeSelector(apiRef.current.state); + + return filterRowTreeFromGroupingColumns({ + rowTree, + isRowMatchingFilters: params.isRowMatchingFilters, + }); + }, + [apiRef], + ); + + const sortingMethod = React.useCallback( + (params) => { + const rowTree = gridRowTreeSelector(apiRef.current.state); + const rowIds = gridRowIdsSelector(apiRef.current.state); + + return sortRowTree({ + rowTree, + rowIds, + sortRowList: params.sortRowList, + comparatorList: params.comparatorList, + disableChildrenSorting: false, + }); + }, + [apiRef], + ); + + useGridRegisterPreProcessor(apiRef, GridPreProcessingGroup.hydrateColumns, updateGroupingColumn); + useGridRegisterPreProcessor(apiRef, GridPreProcessingGroup.columnMenu, addColumnMenuButtons); + useGridRegisterFilteringMethod(apiRef, GROUPING_COLUMNS_FEATURE_NAME, filteringMethod); + useGridRegisterSortingMethod(apiRef, GROUPING_COLUMNS_FEATURE_NAME, sortingMethod); + + /** + * API METHODS + */ + const setGroupingColumnsModel = React.useCallback< + GridGroupingColumnsApi['setGroupingColumnsModel'] + >( + (model) => { + const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + if (currentModel !== model) { + setGridState((state) => ({ + ...state, + groupingColumns: { ...state.groupingColumns, model }, + })); + updateRowGrouping(); + forceUpdate(); + } + }, + [apiRef, setGridState, forceUpdate, updateRowGrouping], + ); + + const addGroupingCriteria = React.useCallback( + (field, groupingIndex) => { + const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + if (currentModel.includes(field)) { + return; + } + + const cleanGroupingIndex = groupingIndex ?? currentModel.length; + + const updatedModel = [ + ...currentModel.slice(0, cleanGroupingIndex), + field, + ...currentModel.slice(cleanGroupingIndex), + ]; + + apiRef.current.setGroupingColumnsModel(updatedModel); + }, + [apiRef], + ); + + const removeGroupingCriteria = React.useCallback< + GridGroupingColumnsApi['removeGroupingCriteria'] + >( + (field) => { + const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + if (!currentModel.includes(field)) { + return; + } + apiRef.current.setGroupingColumnsModel(currentModel.filter((el) => el !== field)); + }, + [apiRef], + ); + + const setGroupingCriteriaIndex = React.useCallback< + GridGroupingColumnsApi['setGroupingCriteriaIndex'] + >( + (field, targetIndex) => { + const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + const currentTargetIndex = currentModel.indexOf(field); + + if (currentTargetIndex === -1) { + return; + } + + const updatedModel = [...currentModel]; + updatedModel.splice(targetIndex, 0, updatedModel.splice(currentTargetIndex, 1)[0]); + + apiRef.current.setGroupingColumnsModel(updatedModel); + }, + [apiRef], + ); + + useGridApiMethod( + apiRef, + { + setGroupingColumnsModel, + addGroupingCriteria, + removeGroupingCriteria, + setGroupingCriteriaIndex, + }, + 'GridGroupingColumnsApi', + ); + + /** + * EVENTS + */ + const handleCellKeyDown = React.useCallback>( + (params, event) => { + const cellParams = apiRef.current.getCellParams(params.id, params.field); + if (isGroupingColumn(cellParams.field) && event.key === ' ' && !event.shiftKey) { + event.stopPropagation(); + event.preventDefault(); + + const filteredDescendantCount = + gridFilteredDescendantCountLookupSelector(apiRef.current.state)[params.id] ?? 0; + + const isOnGroupingCell = + props.groupingColumnMode === 'single' || + getGroupingColDefFieldFromGroupingCriteriaField(params.rowNode.groupingField) === + params.field; + if (!isOnGroupingCell || filteredDescendantCount === 0) { + return; + } + + apiRef.current.setRowChildrenExpansion(params.id, !params.rowNode.childrenExpanded); + } + }, + [apiRef, props.groupingColumnMode], + ); + + const checkGroupingColumnsModelDiff = React.useCallback< + GridEventListener + >(() => { + const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(apiRef.current.state); + const lastGroupingColumnsModelApplied = sanitizedModelOnLastRowPreProcessing.current; + + if (!isDeepEqual(lastGroupingColumnsModelApplied, groupingColumnsModel)) { + sanitizedModelOnLastRowPreProcessing.current = groupingColumnsModel; + + // Refresh the column pre-processing + apiRef.current.updateColumns([]); + updateRowGrouping(); + } + }, [apiRef, updateRowGrouping]); + + useGridApiEventHandler(apiRef, GridEvents.cellKeyDown, handleCellKeyDown); + useGridApiEventHandler(apiRef, GridEvents.columnsChange, checkGroupingColumnsModelDiff); + useGridApiEventHandler( + apiRef, + GridEvents.groupingColumnsModelChange, + checkGroupingColumnsModelDiff, + ); + + /** + * EFFECTS + */ + React.useEffect(() => { + if (props.groupingColumnsModel !== undefined) { + apiRef.current.setGroupingColumnsModel(props.groupingColumnsModel); + } + }, [apiRef, props.groupingColumnsModel]); +}; diff --git a/packages/grid/_modules_/grid/hooks/features/index.ts b/packages/grid/_modules_/grid/hooks/features/index.ts index 85c439a17c153..0bd2576aa7172 100644 --- a/packages/grid/_modules_/grid/hooks/features/index.ts +++ b/packages/grid/_modules_/grid/hooks/features/index.ts @@ -13,3 +13,4 @@ export * from './rows'; export * from './selection'; export * from './sorting'; export * from './dimensions'; +export * from './groupingColumns'; diff --git a/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts b/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts index ea06aeebba98e..2c7e54c196b80 100644 --- a/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts +++ b/packages/grid/_modules_/grid/hooks/features/sorting/useGridSorting.ts @@ -123,6 +123,7 @@ export const useGridSorting = ( const params: GridSortCellParams = { id, field, + rowNode: apiRef.current.getRowNode(id)!, value: apiRef.current.getCellValue(id, field), api: apiRef.current, }; diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts index 769ac7548d550..a24946bc9b531 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts +++ b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts @@ -19,8 +19,9 @@ export const GRID_TREE_DATA_GROUP_COL_DEF: Omit = { field: '__tree_data_group__', editable: false, + canBeGrouped: false, }; diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataUtils.ts b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataUtils.ts index 7cd83e20d863b..41b4b163316f9 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataUtils.ts +++ b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataUtils.ts @@ -1,10 +1,11 @@ import { GridFilterState } from '../filter'; import { GridRowId, GridRowTreeConfig, GridRowTreeNodeConfig } from '../../../models'; +import { GridAggregatedFilterItemApplier } from '../filter/gridFilterState'; interface FilterRowTreeFromTreeDataParams { rowTree: GridRowTreeConfig; disableChildrenFiltering: boolean; - isRowMatchingFilters: ((rowId: GridRowId) => boolean) | null; + isRowMatchingFilters: GridAggregatedFilterItemApplier | null; } /** diff --git a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts index 8840c4673df3d..600c1861e16d3 100644 --- a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts +++ b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts @@ -56,6 +56,8 @@ const DEFAULT_GRID_ICON_SLOTS_COMPONENTS: GridIconSlotsComponent = { MoreActionsIcon: GridMoreVertIcon, TreeDataCollapseIcon: GridExpandLessIcon, TreeDataExpandIcon: GridExpandMoreIcon, + GroupingCriteriaCollapseIcon: GridExpandLessIcon, + GroupingCriteriaExpandIcon: GridExpandMoreIcon, }; const DEFAULT_GRID_SLOTS_COMPONENTS: GridSlotsComponent = { @@ -105,6 +107,8 @@ export const useGridProcessedProps = (inProps: GridInputComponentProps) => { () => ({ ...GRID_DEFAULT_SIMPLE_OPTIONS, ...inProps, + disableGroupingColumns: + inProps.disableGroupingColumns || !inProps.experimentalFeatures?.groupingColumns, localeText, components, }), diff --git a/packages/grid/_modules_/grid/locales/arSD.ts b/packages/grid/_modules_/grid/locales/arSD.ts index c30d6cc05b0bc..c89e64aa50f20 100644 --- a/packages/grid/_modules_/grid/locales/arSD.ts +++ b/packages/grid/_modules_/grid/locales/arSD.ts @@ -114,6 +114,11 @@ const arSDGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const arSD: Localization = getGridLocalization(arSDGrid, arSDCore); diff --git a/packages/grid/_modules_/grid/locales/bgBG.ts b/packages/grid/_modules_/grid/locales/bgBG.ts index 34d76fb70ad37..856a4995408ad 100644 --- a/packages/grid/_modules_/grid/locales/bgBG.ts +++ b/packages/grid/_modules_/grid/locales/bgBG.ts @@ -113,6 +113,11 @@ const bgBGGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const bgBG: Localization = getGridLocalization(bgBGGrid, bgBGCore); diff --git a/packages/grid/_modules_/grid/locales/deDE.ts b/packages/grid/_modules_/grid/locales/deDE.ts index 7cc79c4ba9a71..028a7a75b7118 100644 --- a/packages/grid/_modules_/grid/locales/deDE.ts +++ b/packages/grid/_modules_/grid/locales/deDE.ts @@ -116,6 +116,11 @@ const deDEGrid: Partial = { treeDataGroupingHeaderName: 'Gruppe', treeDataExpand: 'Kinder einblenden', treeDataCollapse: 'Kinder ausblenden', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const deDE: Localization = getGridLocalization(deDEGrid, deDECore); diff --git a/packages/grid/_modules_/grid/locales/elGR.ts b/packages/grid/_modules_/grid/locales/elGR.ts index 7c0544a6b3cf7..1362aea43ca9e 100644 --- a/packages/grid/_modules_/grid/locales/elGR.ts +++ b/packages/grid/_modules_/grid/locales/elGR.ts @@ -115,6 +115,11 @@ const elGRGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const elGR: Localization = getGridLocalization(elGRGrid); diff --git a/packages/grid/_modules_/grid/locales/esES.ts b/packages/grid/_modules_/grid/locales/esES.ts index ff2513d58b51e..b98164faf4ba8 100644 --- a/packages/grid/_modules_/grid/locales/esES.ts +++ b/packages/grid/_modules_/grid/locales/esES.ts @@ -116,6 +116,11 @@ const esESGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const esES: Localization = getGridLocalization(esESGrid, esESCore); diff --git a/packages/grid/_modules_/grid/locales/faIR.ts b/packages/grid/_modules_/grid/locales/faIR.ts index 002b0a5c03cce..b737fcd834e92 100644 --- a/packages/grid/_modules_/grid/locales/faIR.ts +++ b/packages/grid/_modules_/grid/locales/faIR.ts @@ -116,6 +116,11 @@ const faIRGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const faIR: Localization = getGridLocalization(faIRGrid, faIRCore); diff --git a/packages/grid/_modules_/grid/locales/frFR.ts b/packages/grid/_modules_/grid/locales/frFR.ts index 6cd2d423a272a..29c068443dbb2 100644 --- a/packages/grid/_modules_/grid/locales/frFR.ts +++ b/packages/grid/_modules_/grid/locales/frFR.ts @@ -116,6 +116,11 @@ const frFRGrid: Partial = { treeDataGroupingHeaderName: 'Groupe', treeDataExpand: 'afficher les enfants', treeDataCollapse: 'masquer les enfants', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const frFR: Localization = getGridLocalization(frFRGrid, frFRCore); diff --git a/packages/grid/_modules_/grid/locales/heIL.ts b/packages/grid/_modules_/grid/locales/heIL.ts index 3306b69400485..4b3a7e71fed26 100644 --- a/packages/grid/_modules_/grid/locales/heIL.ts +++ b/packages/grid/_modules_/grid/locales/heIL.ts @@ -114,6 +114,11 @@ const heILGrid: Partial = { treeDataGroupingHeaderName: 'קבץ', treeDataExpand: 'הרחב', treeDataCollapse: 'הסתר', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const heIL: Localization = getGridLocalization(heILGrid, heILCore); diff --git a/packages/grid/_modules_/grid/locales/itIT.ts b/packages/grid/_modules_/grid/locales/itIT.ts index 9ee33ed42978a..ae3371312bddf 100644 --- a/packages/grid/_modules_/grid/locales/itIT.ts +++ b/packages/grid/_modules_/grid/locales/itIT.ts @@ -116,6 +116,11 @@ const itITGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const itIT: Localization = getGridLocalization(itITGrid, itITCore); diff --git a/packages/grid/_modules_/grid/locales/jaJP.ts b/packages/grid/_modules_/grid/locales/jaJP.ts index fa9c6060b8386..8be31a9420cde 100644 --- a/packages/grid/_modules_/grid/locales/jaJP.ts +++ b/packages/grid/_modules_/grid/locales/jaJP.ts @@ -111,6 +111,11 @@ const jaJPGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const jaJP: Localization = getGridLocalization(jaJPGrid, jaJPCore); diff --git a/packages/grid/_modules_/grid/locales/koKR.ts b/packages/grid/_modules_/grid/locales/koKR.ts index e3f26a765c8b9..4481bbe752f70 100644 --- a/packages/grid/_modules_/grid/locales/koKR.ts +++ b/packages/grid/_modules_/grid/locales/koKR.ts @@ -111,6 +111,11 @@ const koKRGrid: Partial = { treeDataGroupingHeaderName: '그룹', treeDataExpand: '하위노드 펼치기', treeDataCollapse: '하위노드 접기', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const koKR: Localization = getGridLocalization(koKRGrid, koKRCore); diff --git a/packages/grid/_modules_/grid/locales/nlNL.ts b/packages/grid/_modules_/grid/locales/nlNL.ts index 3f5793a5a1c24..3020237baee82 100644 --- a/packages/grid/_modules_/grid/locales/nlNL.ts +++ b/packages/grid/_modules_/grid/locales/nlNL.ts @@ -115,6 +115,11 @@ const nlNLGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const nlNL: Localization = getGridLocalization(nlNLGrid, nlNLCore); diff --git a/packages/grid/_modules_/grid/locales/plPL.ts b/packages/grid/_modules_/grid/locales/plPL.ts index aeda0abdbd4e5..9961d34b4a72a 100644 --- a/packages/grid/_modules_/grid/locales/plPL.ts +++ b/packages/grid/_modules_/grid/locales/plPL.ts @@ -111,6 +111,11 @@ const plPLGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const plPL: Localization = getGridLocalization(plPLGrid, plPLCore); diff --git a/packages/grid/_modules_/grid/locales/ptBR.ts b/packages/grid/_modules_/grid/locales/ptBR.ts index be0aa19fbea17..7f5a88711b6c2 100644 --- a/packages/grid/_modules_/grid/locales/ptBR.ts +++ b/packages/grid/_modules_/grid/locales/ptBR.ts @@ -116,6 +116,11 @@ const ptBRGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const ptBR: Localization = getGridLocalization(ptBRGrid, ptBRCore); diff --git a/packages/grid/_modules_/grid/locales/ruRU.ts b/packages/grid/_modules_/grid/locales/ruRU.ts index caf26da40d6c3..17d553301fd2a 100644 --- a/packages/grid/_modules_/grid/locales/ruRU.ts +++ b/packages/grid/_modules_/grid/locales/ruRU.ts @@ -144,6 +144,11 @@ const ruRUGrid: Partial = { treeDataGroupingHeaderName: 'Группа', treeDataExpand: 'показать дочерние элементы', treeDataCollapse: 'скрыть дочерние элементы', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const ruRU: Localization = getGridLocalization(ruRUGrid, ruRUCore); diff --git a/packages/grid/_modules_/grid/locales/skSK.ts b/packages/grid/_modules_/grid/locales/skSK.ts index 236c432cc483e..ba2d540ac5c44 100644 --- a/packages/grid/_modules_/grid/locales/skSK.ts +++ b/packages/grid/_modules_/grid/locales/skSK.ts @@ -140,6 +140,11 @@ const skSKGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const skSK: Localization = getGridLocalization(skSKGrid, skSKCore); diff --git a/packages/grid/_modules_/grid/locales/trTR.ts b/packages/grid/_modules_/grid/locales/trTR.ts index ad25e76030f33..83e2ffd9407ea 100644 --- a/packages/grid/_modules_/grid/locales/trTR.ts +++ b/packages/grid/_modules_/grid/locales/trTR.ts @@ -111,6 +111,11 @@ const trTRGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const trTR: Localization = getGridLocalization(trTRGrid, trTRCore); diff --git a/packages/grid/_modules_/grid/locales/ukUA.ts b/packages/grid/_modules_/grid/locales/ukUA.ts index e7e8abce10a86..fff8271aec931 100644 --- a/packages/grid/_modules_/grid/locales/ukUA.ts +++ b/packages/grid/_modules_/grid/locales/ukUA.ts @@ -115,6 +115,11 @@ const ukUAGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const ukUA: Localization = getGridLocalization(ukUAGrid, ukUACore); diff --git a/packages/grid/_modules_/grid/locales/viVN.ts b/packages/grid/_modules_/grid/locales/viVN.ts index 02966d939dff0..cff7b5e2ad892 100644 --- a/packages/grid/_modules_/grid/locales/viVN.ts +++ b/packages/grid/_modules_/grid/locales/viVN.ts @@ -114,6 +114,11 @@ const viVNGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const viVN: Localization = getGridLocalization(viVNGrid, viVNCore); diff --git a/packages/grid/_modules_/grid/locales/zhCN.ts b/packages/grid/_modules_/grid/locales/zhCN.ts index f13c85f18554e..081cd3b8065b8 100644 --- a/packages/grid/_modules_/grid/locales/zhCN.ts +++ b/packages/grid/_modules_/grid/locales/zhCN.ts @@ -112,6 +112,11 @@ const zhCNGrid: Partial = { // treeDataGroupingHeaderName: 'Group', // treeDataExpand: 'see children', // treeDataCollapse: 'hide children', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const zhCN: Localization = getGridLocalization(zhCNGrid, zhCNCore); diff --git a/packages/grid/_modules_/grid/models/api/gridApi.ts b/packages/grid/_modules_/grid/models/api/gridApi.ts index 6c1da4b48341e..718f03d89d1c1 100644 --- a/packages/grid/_modules_/grid/models/api/gridApi.ts +++ b/packages/grid/_modules_/grid/models/api/gridApi.ts @@ -23,6 +23,7 @@ import { GridColumnPinningApi } from './gridColumnPinningApi'; import type { GridPreProcessingApi } from '../../hooks/core/preProcessing'; import type { GridRowGroupsPreProcessingApi } from '../../hooks/core/rowGroupsPerProcessing'; import type { GridDimensionsApi } from '../../hooks/features/dimensions'; +import type { GridGroupingColumnsApi } from '../../hooks/features/groupingColumns'; import type { GridPaginationApi } from '../../hooks/features/pagination'; /** @@ -54,4 +55,5 @@ export interface GridApi GridControlStateApi, GridClipboardApi, GridScrollApi, + GridGroupingColumnsApi, GridColumnPinningApi {} diff --git a/packages/grid/_modules_/grid/models/api/gridLocaleTextApi.ts b/packages/grid/_modules_/grid/models/api/gridLocaleTextApi.ts index 8457c66238771..40aef43bff101 100644 --- a/packages/grid/_modules_/grid/models/api/gridLocaleTextApi.ts +++ b/packages/grid/_modules_/grid/models/api/gridLocaleTextApi.ts @@ -112,6 +112,11 @@ export interface GridLocaleText { treeDataExpand: string; treeDataCollapse: string; + // Grouping columns + groupingColumnHeaderName: string; + groupColumn: (name: string) => string; + unGroupColumn: (name: string) => string; + // Used core components translation keys MuiTablePagination: Omit< ComponentsPropsList['MuiTablePagination'], diff --git a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts index 6fcc959cebcde..a022d575439e2 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts @@ -5,6 +5,7 @@ import { GridColumnHeaderClassNamePropType } from '../gridColumnHeaderClass'; import { GridFilterOperator } from '../gridFilterOperator'; import { GridCellParams, + GridKeyGetterParams, GridRenderCellParams, GridRenderEditCellParams, GridValueFormatterParams, @@ -83,6 +84,11 @@ export interface GridColDef { * @default false */ editable?: boolean; + /** + * If `true`, the rows can be grouped based on this column values (pro-plan only). + * @default true + */ + canBeGrouped?: boolean; /** * A comparator function used to sort rows. */ @@ -106,6 +112,12 @@ export interface GridColDef { * @returns {GridCellValue} The cell value. */ valueGetter?: (params: GridValueGetterParams) => GridCellValue; + /** + * Function that transform a complex cell value into a key that be used for grouping the rows. + * @param {GridKeyGetterParams} params Object containing parameters for the getter. + * @returns {GridKeyValue | null | undefined} The cell key. + */ + keyGetter?: (params: GridKeyGetterParams) => GridKeyValue | null | undefined; /** * Function that allows to customize how the entered value is stored in the row. * It only works with cell/row editing. @@ -229,8 +241,28 @@ export interface GridColumnsMeta { export interface GridGroupingColDefOverride extends Omit< GridColDef, - 'editable' | 'valueSetter' | 'field' | 'preProcessEditCellProps' | 'renderEditCell' + | 'editable' + | 'valueSetter' + | 'field' + | 'type' + | 'preProcessEditCellProps' + | 'renderEditCell' + | 'canBeGrouped' > { + /** + * The field from which we want to apply the sorting and the filtering for the grouping column. + * It is only useful when `props.groupingColumnMode === "multiple"` to decide which grouping criteria should be used for sorting and filtering. + * Do not have any effect when building the tree with the `props.treeData` feature. + * @default: The sorting and filtering is applied based on the leaf field in any, otherwise based on top level grouping criteria. + */ + mainGroupingCriteria?: string; + + /** + * The field from which we want to render the leaves of the tree. + * Do not have any effect when building the tree with the `props.treeData` feature. + */ + leafField?: string; + /** * If `true`, the grouping cells will not render the amount of descendants. * @default: false diff --git a/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts index cbc2031255283..1dba4f2b6bc91 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts @@ -10,6 +10,7 @@ export const GRID_STRING_COL_DEF: GridColTypeDef = { sortable: true, resizable: true, filterable: true, + canBeGrouped: true, sortComparator: gridStringNumberComparer, type: 'string', align: 'left', diff --git a/packages/grid/_modules_/grid/models/events/gridEventLookup.ts b/packages/grid/_modules_/grid/models/events/gridEventLookup.ts index 6daa745ba3c55..7fe6cd86af493 100644 --- a/packages/grid/_modules_/grid/models/events/gridEventLookup.ts +++ b/packages/grid/_modules_/grid/models/events/gridEventLookup.ts @@ -22,6 +22,7 @@ import type { ElementSize } from '../elementSize'; import type { MuiBaseEvent } from '../muiEvent'; import type { GridRowId, GridRowTreeNodeConfig } from '../gridRows'; import type { GridPreProcessingGroup } from '../../hooks/core/preProcessing'; +import type { GridGroupingColumnsModel } from '../../hooks/features/groupingColumns'; import type { GridPinnedColumns } from '../api/gridColumnPinningApi'; export interface GridRowEventLookup { @@ -128,6 +129,7 @@ export interface GridControlledStateEventLookup { sortModelChange: { params: GridSortModel }; editRowsModelChange: { params: GridEditRowsModel }; selectionChange: { params: GridSelectionModel }; + groupingColumnsModelChange: { params: GridGroupingColumnsModel }; pinnedColumnsChange: { params: GridPinnedColumns }; } diff --git a/packages/grid/_modules_/grid/models/events/gridEvents.ts b/packages/grid/_modules_/grid/models/events/gridEvents.ts index 572390b2907bd..c85505bdad9a3 100644 --- a/packages/grid/_modules_/grid/models/events/gridEvents.ts +++ b/packages/grid/_modules_/grid/models/events/gridEvents.ts @@ -205,6 +205,10 @@ export enum GridEvents { * Fired when the page size changes. */ pageSizeChange = 'pageSizeChange', + /** + * Fired when the grouping columns model changes. + */ + groupingColumnsModelChange = 'groupingColumnsModelChange', /** * Fired during the scroll of the grid viewport. */ diff --git a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts index 239f6ed61e8bc..30e2a3556309f 100644 --- a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts +++ b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts @@ -87,4 +87,12 @@ export interface GridIconSlotsComponent { * Icon displayed on the tree data toggling column when the children are expanded */ TreeDataCollapseIcon: React.JSXElementConstructor; + /** + * Icon displayed on the grouping column when the children are collapsed + */ + GroupingCriteriaExpandIcon: React.JSXElementConstructor; + /** + * Icon displayed on the grouping column when the children are expanded + */ + GroupingCriteriaCollapseIcon: React.JSXElementConstructor; } diff --git a/packages/grid/_modules_/grid/models/gridOptions.tsx b/packages/grid/_modules_/grid/models/gridOptions.tsx index b05a93d8dea6a..499a9f90f7555 100644 --- a/packages/grid/_modules_/grid/models/gridOptions.tsx +++ b/packages/grid/_modules_/grid/models/gridOptions.tsx @@ -10,6 +10,14 @@ export type GridMergedOptions = { [key in keyof GridProcessedMergedOptions]: Partial; }; +export enum GridExperimentalFeatures { + /** + * Only available on the Pro plan. + * Will be part of the premium-plan when fully ready. + */ + groupingColumns = 'groupingColumns', +} + /** * The grid options with a default in value which is merged with the value given through props. */ @@ -119,7 +127,7 @@ export interface GridSimpleOptions { */ disableMultipleColumnsFiltering: boolean; /** - * If `true`, the filtering will only be applied to the top level rows. + * If `true`, the filtering will only be applied to the top level rows when grouping rows with the `treeData` prop. * @default false */ disableChildrenFiltering: boolean; @@ -134,7 +142,7 @@ export interface GridSimpleOptions { */ disableMultipleColumnsSorting: boolean; /** - * If `true`, the sorting will only be applied to the top level rows. + * If `true`, the sorting will only be applied to the top level rows when grouping rows with the `treeData` prop. * @default false */ disableChildrenSorting: boolean; @@ -153,6 +161,11 @@ export interface GridSimpleOptions { * @default false */ disableColumnPinning: boolean; + /** + * If `true`, the grouping columns are disabled. + * @default false + */ + disableGroupingColumns: boolean; /** * Controls whether to use the cell or row editing. * @default "cell" @@ -227,6 +240,12 @@ export interface GridSimpleOptions { * @default false */ treeData: boolean; + /** + * If `single`, all column we are grouping by will be represented in the same grouping the same column. + * If `multiple`, each column we are grouping by will be represented in its own column. + * @default 'single' + */ + groupingColumnMode: 'single' | 'multiple'; /** * If above 0, the row children will be expanded up to this depth. * If equal to -1, all the row children will be expanded. @@ -296,6 +315,7 @@ export const GRID_DEFAULT_SIMPLE_OPTIONS: GridSimpleOptions = { disableChildrenSorting: false, disableSelectionOnClick: false, disableVirtualization: false, + disableGroupingColumns: false, editMode: GridEditModes.Cell, filterMode: GridFeatureModeConstant.client, headerHeight: 56, @@ -310,6 +330,7 @@ export const GRID_DEFAULT_SIMPLE_OPTIONS: GridSimpleOptions = { rowHeight: 52, rowsPerPageOptions: [25, 50, 100], treeData: false, + groupingColumnMode: 'single', defaultGroupingExpansionDepth: 0, scrollEndThreshold: 80, showCellRightBorder: false, diff --git a/packages/grid/_modules_/grid/models/gridRows.ts b/packages/grid/_modules_/grid/models/gridRows.ts index b55acfb425e50..b363e8f102caf 100644 --- a/packages/grid/_modules_/grid/models/gridRows.ts +++ b/packages/grid/_modules_/grid/models/gridRows.ts @@ -25,6 +25,7 @@ export interface GridRowTreeNodeConfig { id: GridRowId; /** * The id of the row children. + * @default [] */ children?: GridRowId[]; /** @@ -33,6 +34,7 @@ export interface GridRowTreeNodeConfig { parent: GridRowId | null; /** * Current expansion status of the row. + * @default false */ childrenExpanded?: boolean; /** @@ -50,6 +52,7 @@ export interface GridRowTreeNodeConfig { groupingField: string | null; /** * If `true`, this node has been automatically added to fill a gap in the tree structure. + * @default false */ isAutoGenerated?: boolean; } diff --git a/packages/grid/_modules_/grid/models/gridSortModel.ts b/packages/grid/_modules_/grid/models/gridSortModel.ts index d344b71a6b7dd..ed3e98caedfff 100644 --- a/packages/grid/_modules_/grid/models/gridSortModel.ts +++ b/packages/grid/_modules_/grid/models/gridSortModel.ts @@ -1,5 +1,5 @@ import { GridCellValue } from './gridCell'; -import { GridRowId } from './gridRows'; +import { GridRowId, GridRowTreeNodeConfig } from './gridRows'; import type { GridApi } from './api'; export type GridSortDirection = 'asc' | 'desc' | null | undefined; @@ -8,6 +8,7 @@ export interface GridSortCellParams { id: GridRowId; field: string; value: GridCellValue; + rowNode: GridRowTreeNodeConfig; api: GridApi; } diff --git a/packages/grid/_modules_/grid/models/gridState.ts b/packages/grid/_modules_/grid/models/gridState.ts index 4693f94bf343e..740581083702f 100644 --- a/packages/grid/_modules_/grid/models/gridState.ts +++ b/packages/grid/_modules_/grid/models/gridState.ts @@ -20,8 +20,15 @@ import type { GridFilterState, GridFilterInitialState, } from '../hooks/features/filter/gridFilterState'; +import type { + GridGroupingColumnsState, + GridGroupingColumnsInitialState, +} from '../hooks/features/groupingColumns'; import { GridColumnPinningState } from '../hooks/features/columnPinning/gridColumnPinningState'; +/** + * TODO: Distinguish pro and community states + */ export interface GridState { rows: GridRowsState; editRows: GridEditRowsModel; @@ -37,6 +44,7 @@ export interface GridState { filter: GridFilterState; preferencePanel: GridPreferencePanelState; density: GridDensityState; + groupingColumns: GridGroupingColumnsState; error?: any; pinnedColumns: GridColumnPinningState; } @@ -45,5 +53,6 @@ export interface GridInitialState { sorting?: GridSortingInitialState; filter?: GridFilterInitialState; preferencePanel?: GridPreferencePanelInitialState; + groupingColumns?: GridGroupingColumnsInitialState; pinnedColumns?: GridColumnPinningState; } diff --git a/packages/grid/_modules_/grid/models/params/gridCellParams.ts b/packages/grid/_modules_/grid/models/params/gridCellParams.ts index 09a212ef33ac4..cf7599a9a2746 100644 --- a/packages/grid/_modules_/grid/models/params/gridCellParams.ts +++ b/packages/grid/_modules_/grid/models/params/gridCellParams.ts @@ -109,7 +109,7 @@ export interface GridValueGetterSimpleParams { */ id: GridRowId; /** - * The column field of the cell that triggered the event + * The column field of the cell that triggered the event. */ field: string; /** @@ -155,7 +155,7 @@ export interface GridValueFormatterParams { */ id?: GridRowId; /** - * The column field of the cell that triggered the event + * The column field of the cell that triggered the event. */ field: string; /** @@ -185,3 +185,21 @@ export interface GridPreProcessEditCellProps { */ props: GridEditCellProps; } + +/** + * Object passed as parameter in the column [[GridColDef]] key getter callback. + */ +export interface GridKeyGetterParams { + /** + * The grid row id. + */ + id: GridRowId; + /** + * The column field of the cell that triggered the event. + */ + field: string; + /** + * The cell value (if the column has valueGetter, this is the value returned by it). + */ + value: V; +} diff --git a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts index ffef752df7239..304722be087b6 100644 --- a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts +++ b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts @@ -1,7 +1,6 @@ import { expect } from 'chai'; import { buildRowTree } from './buildRowTree'; -// TODO: Add tests for multi-field grouping describe('buildRowTree', () => { it('should not expand the rows when defaultGroupingExpansionDepth === 0', () => { const response = buildRowTree({ @@ -274,4 +273,90 @@ describe('buildRowTree', () => { }, }); }); + + it('should allow to have two rows with the same field at various depth', () => { + const response = buildRowTree({ + groupingName: '', + idRowsLookup: { + 0: {}, + 1: {}, + }, + ids: [0, 1], + rows: [ + { + id: 0, + path: [ + { key: 'value-1-1', field: 'field1' }, + { key: 'value-2-1', field: 'field2' }, + { key: 'value-leaf-1', field: null }, + ], + }, + { + id: 1, + path: [ + { key: 'value-2-1', field: 'field2' }, + { key: 'value-leaf-1', field: null }, + ], + }, + ], + defaultGroupingExpansionDepth: -1, + }); + + // The tree structure: + // "value-1-1" + // "value-2-1" + // "value-leaf-1" + // "value-2-1" + // "value-leaf-1" + expect(response.tree).to.deep.equal({ + '0': { + id: 0, + childrenExpanded: true, + parent: 'auto-generated-row-field1/value-1-1-field2/value-2-1', + groupingKey: 'value-leaf-1', + groupingField: null, + depth: 2, + children: undefined, + }, + '1': { + id: 1, + childrenExpanded: true, + parent: 'auto-generated-row-field2/value-2-1', + groupingKey: 'value-leaf-1', + groupingField: null, + depth: 1, + children: undefined, + }, + 'auto-generated-row-field1/value-1-1': { + id: 'auto-generated-row-field1/value-1-1', + isAutoGenerated: true, + childrenExpanded: true, + parent: null, + groupingKey: 'value-1-1', + groupingField: 'field1', + depth: 0, + children: ['auto-generated-row-field1/value-1-1-field2/value-2-1'], + }, + 'auto-generated-row-field1/value-1-1-field2/value-2-1': { + id: 'auto-generated-row-field1/value-1-1-field2/value-2-1', + isAutoGenerated: true, + childrenExpanded: true, + parent: 'auto-generated-row-field1/value-1-1', + groupingKey: 'value-2-1', + groupingField: 'field2', + depth: 1, + children: [0], + }, + 'auto-generated-row-field2/value-2-1': { + id: 'auto-generated-row-field2/value-2-1', + isAutoGenerated: true, + childrenExpanded: true, + parent: null, + groupingKey: 'value-2-1', + groupingField: 'field2', + depth: 0, + children: [1], + }, + }); + }); }); diff --git a/packages/grid/x-data-grid-generator/src/commodities.columns.tsx b/packages/grid/x-data-grid-generator/src/commodities.columns.tsx index 4fa58cefcd793..ffc5d67825e80 100644 --- a/packages/grid/x-data-grid-generator/src/commodities.columns.tsx +++ b/packages/grid/x-data-grid-generator/src/commodities.columns.tsx @@ -146,7 +146,8 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'subTotal', headerName: 'Sub Total', - valueGetter: ({ row }) => row.quantity * row.unitPrice, + valueGetter: ({ row, rowNode }) => + rowNode.isAutoGenerated ? null : row.quantity * row.unitPrice, type: 'number', width: 120, }, @@ -163,7 +164,8 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'feeAmount', headerName: 'Fee Amount', - valueGetter: ({ row }) => row.feeRate * row.quantity * row.unitPrice, + valueGetter: ({ row, rowNode }) => + rowNode.isAutoGenerated ? null : row.feeRate * row.quantity * row.unitPrice, type: 'number', width: 120, }, @@ -179,7 +181,8 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => { field: 'totalPrice', headerName: 'Total in USD', - valueGetter: ({ row }) => row.feeRate + row.quantity * row.unitPrice, + valueGetter: ({ row, rowNode }) => + rowNode.isAutoGenerated ? null : row.feeRate + row.quantity * row.unitPrice, renderCell: renderTotalPrice, type: 'number', width: 160, @@ -239,6 +242,7 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => return value; }, + keyGetter: (params) => params.value.code, type: 'singleSelect', valueOptions: COUNTRY_ISO_OPTIONS, editable, diff --git a/packages/grid/x-data-grid-generator/src/index.ts b/packages/grid/x-data-grid-generator/src/index.ts index a5590f5ed67e6..2adc86aa857a4 100644 --- a/packages/grid/x-data-grid-generator/src/index.ts +++ b/packages/grid/x-data-grid-generator/src/index.ts @@ -3,3 +3,4 @@ export * from './services'; export * from './commodities.columns'; export * from './employees.columns'; export * from './useDemoData'; +export * from './useMovieData'; diff --git a/packages/grid/x-data-grid-generator/src/renderer/renderCountry.tsx b/packages/grid/x-data-grid-generator/src/renderer/renderCountry.tsx index 7352962d87d60..a0a28c4971bee 100644 --- a/packages/grid/x-data-grid-generator/src/renderer/renderCountry.tsx +++ b/packages/grid/x-data-grid-generator/src/renderer/renderCountry.tsx @@ -49,5 +49,9 @@ const Country = React.memo(function Country(props: CountryProps) { }); export function renderCountry(params: GridRenderCellParams) { + if (params.rowNode.isAutoGenerated) { + return ''; + } + return ; } diff --git a/packages/grid/x-data-grid-generator/src/renderer/renderPnl.tsx b/packages/grid/x-data-grid-generator/src/renderer/renderPnl.tsx index 8f6f1cabab989..55fa5c49df371 100644 --- a/packages/grid/x-data-grid-generator/src/renderer/renderPnl.tsx +++ b/packages/grid/x-data-grid-generator/src/renderer/renderPnl.tsx @@ -49,5 +49,9 @@ const Pnl = React.memo(function Pnl(props: PnlProps) { }); export function renderPnl(params: GridCellParams) { + if (params.rowNode.isAutoGenerated) { + return ''; + } + return ; } diff --git a/packages/grid/x-data-grid-generator/src/renderer/renderProgress.tsx b/packages/grid/x-data-grid-generator/src/renderer/renderProgress.tsx index 8c235fa18e13a..c18647de9c15d 100644 --- a/packages/grid/x-data-grid-generator/src/renderer/renderProgress.tsx +++ b/packages/grid/x-data-grid-generator/src/renderer/renderProgress.tsx @@ -64,5 +64,9 @@ const ProgressBar = React.memo(function ProgressBar(props: ProgressBarProps) { }); export function renderProgress(params: GridCellParams) { + if (params.rowNode.isAutoGenerated) { + return ''; + } + return ; } diff --git a/packages/grid/x-data-grid-generator/src/renderer/renderStatus.tsx b/packages/grid/x-data-grid-generator/src/renderer/renderStatus.tsx index d9fd9dfd77c1e..11986b3c53464 100644 --- a/packages/grid/x-data-grid-generator/src/renderer/renderStatus.tsx +++ b/packages/grid/x-data-grid-generator/src/renderer/renderStatus.tsx @@ -74,5 +74,9 @@ const Status = React.memo((props: StatusProps) => { }); export function renderStatus(params: GridCellParams) { - return ; + if (params.rowNode.isAutoGenerated) { + return ''; + } + + return ; } diff --git a/packages/grid/x-data-grid-generator/src/renderer/renderTotalPrice.tsx b/packages/grid/x-data-grid-generator/src/renderer/renderTotalPrice.tsx index ad81fa698d25d..2861f2b03b22f 100644 --- a/packages/grid/x-data-grid-generator/src/renderer/renderTotalPrice.tsx +++ b/packages/grid/x-data-grid-generator/src/renderer/renderTotalPrice.tsx @@ -48,5 +48,8 @@ const TotalPrice = React.memo(function TotalPrice(props: TotalPriceProps) { }); export function renderTotalPrice(params: GridCellParams) { + if (params.rowNode.isAutoGenerated) { + return ''; + } return ; } diff --git a/packages/grid/x-data-grid-generator/src/useMovieData.ts b/packages/grid/x-data-grid-generator/src/useMovieData.ts new file mode 100644 index 0000000000000..4a032f9bd7f92 --- /dev/null +++ b/packages/grid/x-data-grid-generator/src/useMovieData.ts @@ -0,0 +1,284 @@ +import { GridColumns, GridComponentProps, GridRowModel } from '@mui/x-data-grid'; + +type Movie = { + title: string; + gross: number; + director: string; + company: string; + year: number; + composer: { name: string }; + cinematicUniverse?: string; +}; + +const COLUMNS: GridColumns = [ + { field: 'title', headerName: 'Title', width: 200, canBeGrouped: false }, + { + field: 'gross', + headerName: 'Gross', + type: 'number', + width: 150, + canBeGrouped: false, + valueFormatter: ({ value }) => { + if (!value || typeof value !== 'number') { + return value; + } + return `${value.toLocaleString()}$`; + }, + }, + { + field: 'company', + headerName: 'Company', + width: 200, + }, + { + field: 'director', + headerName: 'Director', + width: 200, + }, + { + field: 'year', + headerName: 'Year', + }, + { + field: 'cinematicUniverse', + headerName: 'Cinematic Universe', + width: 220, + }, +]; + +const ROWS: GridRowModel[] = [ + { + title: 'Avatar', + gross: 2847246203, + director: 'James Cameron', + company: '20th Century Fox', + year: 2009, + composer: { + name: 'James Horner', + }, + }, + { + title: 'Avengers: Endgame', + gross: 2797501328, + director: 'Anthony & Joe Russo', + company: 'Disney Studios', + year: 2019, + cinematicUniverse: 'Marvel Cinematic Universe', + composer: { + name: 'Alan Silvestri', + }, + }, + { + title: 'Titanic', + gross: 2187425379, + director: 'James Cameron', + company: '20th Century Fox', + year: 1997, + composer: { + name: 'James Horner', + }, + }, + { + title: 'Star Wars: The Force Awakens', + gross: 2068223624, + director: 'J. J. Abrams', + company: 'Disney Studios', + year: 2015, + cinematicUniverse: 'Star Wars', + composer: { + name: 'John Williams', + }, + }, + { + title: 'Avengers: Infinity War', + gross: 2048359754, + director: 'Anthony & Joe Russo', + company: 'Disney Studios', + year: 2018, + cinematicUniverse: 'Star Wars', + composer: { + name: 'Alan Silvestri', + }, + }, + { + title: 'Jurassic World', + gross: 1671713208, + director: 'Colin Trevorrow', + company: 'Universal Pictures', + year: 2015, + cinematicUniverse: 'Jurassic Park', + composer: { + name: 'Michael Giacchino', + }, + }, + { + title: 'The Lion King', + gross: 1656943394, + director: 'Jon Favreau', + company: 'Disney Studios', + year: 2019, + composer: { + name: 'Hans Zimmer', + }, + }, + { + title: 'The Avengers', + gross: 1518812988, + director: 'Joss Whedon', + company: 'Disney Studios', + year: 2012, + cinematicUniverse: 'Marvel Cinematic Universe', + composer: { + name: 'Alan Silvestri', + }, + }, + { + title: 'Furious 7', + gross: 1516045911, + director: 'James Wan', + company: 'Universal Pictures', + year: 2015, + cinematicUniverse: 'Fast & Furious', + composer: { + name: 'Brian Tyler', + }, + }, + { + title: 'Frozen II', + gross: 1450026933, + director: 'Chris Buck & Jennifer Lee', + company: 'Disney Studios', + year: 2019, + cinematicUniverse: 'Frozen', + composer: { + name: 'Christophe Beck', + }, + }, + { + title: 'Avengers: Age of Ultron', + gross: 1402804868, + director: 'Joss Whedon', + company: 'Disney Studios', + year: 2015, + cinematicUniverse: 'Marvel Cinematic Universe', + composer: { + name: 'Danny Elfman', + }, + }, + { + title: 'Black Panther', + gross: 1347280838, + director: 'Ryan Coogler', + company: 'Disney Studios', + year: 2018, + cinematicUniverse: 'Marvel Cinematic Universe', + composer: { + name: 'Ludwig Göransson', + }, + }, + { + title: 'Harry Potter and the Deathly Hallows – Part 2', + gross: 1342025430, + director: 'David Yates', + company: 'Warner Bros. Pictures', + year: 2011, + composer: { + name: 'Alexandre Desplat', + }, + }, + { + title: 'Star Wars: The Last Jedi', + gross: 1332539889, + director: 'Rian Johnson', + company: 'Disney Studios', + year: 2017, + cinematicUniverse: 'Star Wars', + composer: { + name: 'John Williams', + }, + }, + { + title: 'Jurassic World: Fallen Kingdom', + gross: 1309484461, + director: 'J. A. Bayona', + company: 'Universal Pictures', + year: 2018, + cinematicUniverse: 'Jurassic Park', + composer: { + name: 'Michael Giacchino', + }, + }, + { + title: 'Frozen', + gross: 1290000000, + director: 'Chris Buck & Jennifer Lee', + company: 'Disney Studios', + year: 2013, + cinematicUniverse: 'Frozen', + composer: { + name: 'Christophe Beck', + }, + }, + { + title: 'Beauty and the Beast', + gross: 1263521136, + director: 'Bill Condon', + company: 'Disney Studios', + year: 2017, + composer: { + name: 'Alan Menken', + }, + }, + { + title: 'Incredibles 2', + gross: 1242805359, + director: 'Brad Bird', + company: 'Disney Studios', + year: 2018, + composer: { + name: 'Michael Giacchino', + }, + }, + { + title: 'The Fate of the Furious', + gross: 1238764765, + director: 'F. Gary Gray', + company: 'Universal Pictures', + year: 2017, + cinematicUniverse: 'Fast & Furious', + composer: { + name: 'Brian Tyler', + }, + }, + { + title: 'Iron Man 3', + gross: 1214811252, + director: 'Shane Black', + company: 'Disney Studios', + year: 2013, + cinematicUniverse: 'Marvel Cinematic Universe', + composer: { + name: 'Brian Tyler', + }, + }, + { + title: 'Minions', + gross: 11159398397, + director: 'Pierre Coffin & Kyle Balda', + company: 'Universal Pictures', + year: 2015, + composer: { + name: 'Heitor Pereira', + }, + }, +]; + +const getRowId = (row: any) => row.title; + +export const useMovieData = (): Pick => { + return { + getRowId, + rows: ROWS, + columns: COLUMNS, + }; +}; diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx index 67df381dac00e..b7fa7cfc48fe2 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx @@ -147,12 +147,12 @@ DataGridProRaw.propTypes = { */ density: PropTypes.oneOf(['comfortable', 'compact', 'standard']), /** - * If `true`, the filtering will only be applied to the top level rows. + * If `true`, the filtering will only be applied to the top level rows when grouping rows with the `treeData` prop. * @default false */ disableChildrenFiltering: PropTypes.bool, /** - * If `true`, the sorting will only be applied to the top level rows. + * If `true`, the sorting will only be applied to the top level rows when grouping rows with the `treeData` prop. * @default false */ disableChildrenSorting: PropTypes.bool, @@ -196,6 +196,11 @@ DataGridProRaw.propTypes = { * @default false */ disableExtendRowFullWidth: PropTypes.bool, + /** + * If `true`, the grouping columns are disabled. + * @default false + */ + disableGroupingColumns: PropTypes.bool, /** * If `true`, filtering with multiple columns is disabled. * @default false @@ -234,6 +239,13 @@ DataGridProRaw.propTypes = { * An error that will turn the grid into its error state and display the error component. */ error: PropTypes.any, + /** + * Features under development. + * For each feature, if the flag is not explicitly set to `true`, the feature will be fully disabled and any property / method call will not have any effect. + */ + experimentalFeatures: PropTypes.shape({ + groupingColumns: PropTypes.bool, + }), /** * Filtering can be processed on the server or client-side. * Set it to 'server' if you would like to handle filtering on the server-side. @@ -289,6 +301,16 @@ DataGridProRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + /** + * If `single`, all column we are grouping by will be represented in the same grouping the same column. + * If `multiple`, each column we are grouping by will be represented in its own column. + * @default 'single' + */ + groupingColumnMode: PropTypes.oneOf(['multiple', 'single']), + /** + * Set the grouping columns of the grid. + */ + groupingColumnsModel: PropTypes.arrayOf(PropTypes.string), /** * Set the height in pixel of the column headers in the grid. * @default 56 @@ -512,6 +534,12 @@ DataGridProRaw.propTypes = { * @param {GridCallbackDetails} details Additional details for this callback. */ onFilterModelChange: PropTypes.func, + /** + * Callback fired when the grouping columns model changes. + * @param {GridGroupingColumnsModel} model Columns used as grouping criteria. + * @param {GridCallbackDetails} details Additional details for this callback. + */ + onGroupingColumnsModelChange: PropTypes.func, /** * Callback fired when the current page has changed. * @param {number} page Index of the page displayed on the Grid. diff --git a/packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx new file mode 100644 index 0000000000000..be5649d16e1c8 --- /dev/null +++ b/packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx @@ -0,0 +1,2050 @@ +import { createRenderer, fireEvent, screen, act } from '@material-ui/monorepo/test/utils'; +import { getColumnHeadersTextContent, getColumnValues } from 'test/utils/helperFn'; +import * as React from 'react'; +import { expect } from 'chai'; +import { + DataGridPro, + DataGridProProps, + GridApiRef, + GridKeyGetterParams, + GridPreferencePanelsValue, + GridRowsProp, + useGridApiRef, + useGridRootProps, +} from '@mui/x-data-grid-pro'; +import { spy } from 'sinon'; + +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + +const rows: GridRowsProp = [ + { id: 0, category1: 'Cat A', category2: 'Cat 1' }, + { id: 1, category1: 'Cat A', category2: 'Cat 2' }, + { id: 2, category1: 'Cat A', category2: 'Cat 2' }, + { id: 3, category1: 'Cat B', category2: 'Cat 2' }, + { id: 4, category1: 'Cat B', category2: 'Cat 1' }, +]; + +const unbalancedRows: GridRowsProp = [ + { id: 0, category1: 'Cat A' }, + { id: 1, category1: 'Cat A' }, + { id: 2, category1: 'Cat B' }, + { id: 3, category1: 'Cat B' }, + { id: 4, category1: null }, + { id: 5, category1: null }, +]; + +const baselineProps: DataGridProProps = { + autoHeight: isJSDOM, + disableVirtualization: true, + rows, + columns: [ + { + field: 'id', + type: 'number', + }, + { + field: 'category1', + }, + { + field: 'category2', + }, + ], + experimentalFeatures: { + groupingColumns: true, + }, +}; + +describe(' - Group Rows By Column', () => { + const { render, clock } = createRenderer({ clock: 'fake' }); + + let apiRef: GridApiRef; + + const Test = (props: Partial) => { + apiRef = useGridApiRef(); + + return ( +
+ +
+ ); + }; + + describe('Setting grouping criteria', () => { + describe('initialState: groupingColumns.model', () => { + it('should allow to initialize the grouping columns', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + }); + + it('should not react to initial state updates', () => { + const { setProps } = render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + + setProps({ initialState: { groupingColumns: { model: ['category2'] } } }); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + }); + }); + + describe('prop: groupingColumnsModel', () => { + it('should not call onGroupingColumnsModelChange on initialisation or on groupingColumnsModel prop change', () => { + const onGroupingColumnsModelChange = spy(); + + const { setProps } = render( + , + ); + + expect(onGroupingColumnsModelChange.callCount).to.equal(0); + setProps({ groupingColumnsModel: ['category2'] }); + + expect(onGroupingColumnsModelChange.callCount).to.equal(0); + }); + + it('should allow to update the grouping columns model from the outside', () => { + const { setProps } = render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + setProps({ groupingColumnsModel: ['category2'] }); + expect(getColumnValues()).to.deep.equal(['Cat 1 (2)', '', '', 'Cat 2 (3)', '', '', '']); + setProps({ groupingColumnsModel: ['category1', 'category2'] }); + expect(getColumnValues()).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + }); + + it('should ignore grouping criteria that do not match any column', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + }); + + it('should ignore grouping criteria with colDef.canBeGrouped = false', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); + }); + + it('should allow to use several time the same grouping criteria', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat A (3)', + '', + '', + '', + 'Cat B (2)', + 'Cat B (2)', + '', + '', + ]); + }); + }); + + describe('props: groupingColumnMode', () => { + it('should gather all the grouping criteria into a single column when groupingColumnMode is not defined', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Group', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should gather all the grouping criteria into a single column when groupingColumnMode = "single"', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Group', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should create one grouping column per grouping criteria when groupingColumnMode = "multiple"', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category1', + 'category2', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + '', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should support groupingColumnMode switch', () => { + const { setProps } = render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category1', + 'category2', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + '', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + + setProps({ groupingColumnMode: 'single' }); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Group', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + + setProps({ groupingColumnMode: 'multiple' }); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category1', + 'category2', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + '', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should respect the model grouping order when groupingColumnMode = "single"', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Group', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat 1 (2)', + 'Cat A (1)', + '', + 'Cat B (1)', + '', + 'Cat 2 (3)', + 'Cat A (2)', + '', + '', + 'Cat B (1)', + '', + ]); + }); + + it('should respect the model grouping order when groupingColumnMode = "multiple"', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category2', + 'category1', + 'id', + 'category1', + 'category2', + ]); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat 1 (2)', + '', + '', + '', + '', + 'Cat 2 (3)', + '', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat A (1)', + '', + 'Cat B (1)', + '', + '', + 'Cat A (2)', + '', + '', + 'Cat B (1)', + '', + ]); + }); + }); + + describe('props: disableGroupingColumns', () => { + // TODO: Remove once the feature is stable + it('should set `disableGroupingColumns` to `true` if `experimentalFeatures.groupingColumns = false', () => { + const disableGroupingColumnsSpy = spy(); + + const CustomToolbar = () => { + const rootProps = useGridRootProps(); + disableGroupingColumnsSpy(rootProps.disableGroupingColumns); + return null; + }; + + render( + , + ); + + expect(disableGroupingColumnsSpy.lastCall.firstArg).to.equal(true); + }); + + it('should disable grouping columns when `prop.disableGroupingColumns = true`', () => { + render( + , + ); + + // No grouping applied on rows + expect(apiRef.current.state.rows.groupingName).to.equal('none'); + expect(getColumnValues(0)).to.deep.equal(['0', '1', '2', '3', '4']); + + // No grouping column rendered + expect(getColumnHeadersTextContent()).to.deep.equal(['id', 'category1', 'category2']); + + // No menu item on column menu to add / remove grouping criteria + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const category1Menuitem = screen.queryByRole('menuitem', { + name: 'Stop grouping by category1', + }); + expect(category1Menuitem).to.equal(null); + + apiRef.current.hideColumnMenu(); + clock.runToLast(); + expect(screen.queryByRole('menu')).to.equal(null); + + apiRef.current.showColumnMenu('category2'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const category2Menuitem = screen.queryByRole('menuitem', { name: 'Group by category2' }); + expect(category2Menuitem).to.equal(null); + }); + }); + + describe('prop: defaultGroupingExpansionDepth', () => { + it('should not expand any row if defaultGroupingExpansionDepth = 0', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); + }); + + it('should expand all top level rows if defaultGroupingExpansionDepth = 1', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + 'Cat 2 (2)', + 'Cat B (2)', + 'Cat 2 (1)', + 'Cat 1 (1)', + ]); + }); + + it('should expand all rows up to depth of 2 if defaultGroupingExpansionDepth = 2', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should expand all rows if defaultGroupingExpansionDepth = -1', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should react to defaultGroupingExpansionDepth updates', () => { + const { setProps } = render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); + setProps({ defaultGroupingExpansionDepth: 1 }); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + 'Cat 2 (2)', + 'Cat B (2)', + 'Cat 2 (1)', + 'Cat 1 (1)', + ]); + }); + + it('should not re-apply default expansion on rerender after expansion manually toggled', () => { + const { setProps } = render( + , + ); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); + act(() => { + apiRef.current.setRowChildrenExpansion('auto-generated-row-category1/Cat B', true); + }); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat B (2)', + 'Cat 2 (1)', + 'Cat 1 (1)', + ]); + setProps({ sortModel: [{ field: '__row_group_by_columns_group__', sort: 'desc' }] }); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat B (2)', + 'Cat 2 (1)', + 'Cat 1 (1)', + 'Cat A (3)', + ]); + }); + }); + + describe('props: groupingColDef when groupingColumMode = "single"', () => { + it('should not allow to override the field', () => { + const { setProps } = render( + + params.fields.includes('category1') + ? { + headerName: 'Custom group', + } + : {} + } + />, + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Custom group', + 'category2', + 'id', + 'category1', + 'category2', + ]); + + setProps({ + groupingColDef: (params) => + params.fields.includes('category2') + ? { + headerName: 'Custom group', + } + : {}, + }); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category1', + 'Custom group', + 'id', + 'category1', + 'category2', + ]); + }); + + it('should react to groupingColDef update', () => {}); + + describe('prop: groupColDef.leafField', () => { + it('should render the leafField `value` on leaves', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '0', + '1', + '2', + 'Cat B (2)', + '3', + '4', + ]); + }); + + it('should render the leafField `formattedValue` on leaves if `valueFormatter` is defined on the leafColDef', () => { + render( + { + if (params.value == null) { + return null; + } + + return `#${params.value}`; + }, + }, + { + field: 'category1', + }, + ]} + initialState={{ groupingColumns: { model: ['category1'] } }} + groupingColumnMode="single" + groupingColDef={{ leafField: 'id' }} + defaultGroupingExpansionDepth={-1} + />, + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '#0', + '#1', + '#2', + 'Cat B (2)', + '#3', + '#4', + ]); + }); + + it('should render the leafField `renderCell` on leaves if `renderCell` is defined on the leafColDef', () => { + const renderIdCell = spy(() => 'Custom leaf'); + + render( + , + ); + + expect(renderIdCell.lastCall.firstArg.id).to.equal(4); + expect(renderIdCell.lastCall.firstArg.field).to.equal('id'); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Custom leaf', + 'Custom leaf', + 'Custom leaf', + 'Cat B (2)', + 'Custom leaf', + 'Custom leaf', + ]); + }); + }); + + describe('prop: groupColDef.headerName', () => { + it('should allow to override the headerName in object mode', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Main category', + 'id', + 'category1', + 'category2', + ]); + }); + + it('should allow to override the headerName in callback mode', () => { + render( + + params.fields.includes('category1') + ? { + headerName: 'Main category', + } + : {} + } + />, + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Main category', + 'id', + 'category1', + 'category2', + ]); + }); + }); + + describe('prop: groupingColDef.hideDescendantCount', () => { + it('should render descendant count when hideDescendantCount = false', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should not render descendant count when hideDescendantCount = true', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A', + 'Cat 1', + '', + 'Cat 2', + '', + '', + 'Cat B', + 'Cat 2', + '', + 'Cat 1', + '', + ]); + }); + }); + }); + + describe('props: groupingColDef when groupingColumMode = "multiple"', () => { + it('should not allow to override the field', () => { + render( + , + ); + + expect(apiRef.current.getAllColumns()[0].field).to.equal('__row_group_by_columns_group__'); + }); + + describe('prop: groupColDef.leafField', () => { + it('should render the leafField `value` on leaves', () => { + render( + + params.fields.includes('category2') + ? { + leafField: 'id', + } + : {} + } + defaultGroupingExpansionDepth={-1} + />, + ); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '0', + 'Cat 2 (2)', + '1', + '2', + '', + 'Cat 2 (1)', + '3', + 'Cat 1 (1)', + '4', + ]); + }); + + it('should render the leafField `formattedValue` on leaves if `valueFormatter` is defined on the leafColDef', () => { + render( + { + if (params.value == null) { + return null; + } + + return `#${params.value}`; + }, + }, + { + field: 'category1', + }, + { + field: 'category2', + }, + ]} + initialState={{ groupingColumns: { model: ['category1', 'category2'] } }} + groupingColumnMode="multiple" + groupingColDef={(params) => + params.fields.includes('category2') + ? { + leafField: 'id', + } + : {} + } + defaultGroupingExpansionDepth={-1} + />, + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '#0', + 'Cat 2 (2)', + '#1', + '#2', + '', + 'Cat 2 (1)', + '#3', + 'Cat 1 (1)', + '#4', + ]); + }); + + it('should render the leafField `renderCell` on leaves if `renderCell` is defined on the leafColDef', () => { + const renderIdCell = spy(() => 'Custom leaf'); + + render( + + params.fields.includes('category2') + ? { + leafField: 'id', + } + : {} + } + defaultGroupingExpansionDepth={-1} + />, + ); + + expect(renderIdCell.lastCall.firstArg.id).to.equal(4); + expect(renderIdCell.lastCall.firstArg.field).to.equal('id'); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + 'Custom leaf', + 'Cat 2 (2)', + 'Custom leaf', + 'Custom leaf', + '', + 'Cat 2 (1)', + 'Custom leaf', + 'Cat 1 (1)', + 'Custom leaf', + ]); + }); + }); + + describe('prop: groupColDef.headerName', () => { + it('should allow to override the headerName in object mode', () => { + render( + , + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Main category', + 'Main category', + 'id', + 'category1', + 'category2', + ]); + }); + + it('should allow to override the headerName in callback mode', () => { + render( + + params.fields.includes('category1') + ? { + headerName: 'Main category', + } + : {} + } + />, + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Main category', + 'category2', + 'id', + 'category1', + 'category2', + ]); + }); + }); + + describe('prop: groupingColDef.hideDescendantCount', () => { + it('should render descendant count when hideDescendantCount = false', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '', + '', + '', + '', + '', + 'Cat B (2)', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + '', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + ]); + }); + + it('should not render descendant count when hideDescendantCount = true', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A', + '', + '', + '', + '', + '', + 'Cat B', + '', + '', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal([ + '', + 'Cat 1', + '', + 'Cat 2', + '', + '', + '', + 'Cat 2', + '', + 'Cat 1', + '', + ]); + }); + }); + }); + + describe('colDef: keyGetter & valueGetter', () => { + it('should use keyGetter to group rows when defined', () => { + render( + ) => `key ${params.value}`, + }, + ]} + initialState={{ groupingColumns: { model: ['category1'] } }} + defaultGroupingExpansionDepth={-1} + />, + ); + expect(getColumnValues(0)).to.deep.equal([ + 'key Cat A (3)', + '', + '', + '', + 'key Cat B (2)', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '3', '4']); + }); + + it('should use valueGetter to group the rows when defined', () => { + render( + `value ${params.row.category1}`, + }, + ]} + initialState={{ groupingColumns: { model: ['complexCategory1'] } }} + defaultGroupingExpansionDepth={-1} + />, + ); + expect(getColumnValues(0)).to.deep.equal([ + 'value Cat A (3)', + '', + '', + '', + 'value Cat B (2)', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '3', '4']); + }); + + it('should pass the return value of valueGetter to the keyGetter callback when both defined', () => { + render( + `value ${params.row.category1}`, + keyGetter: (params: GridKeyGetterParams) => `key ${params.value}`, + }, + ]} + defaultGroupingExpansionDepth={-1} + />, + ); + expect(getColumnValues(0)).to.deep.equal([ + 'key value Cat A (3)', + '', + '', + '', + 'key value Cat B (2)', + '', + '', + ]); + expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '3', '4']); + }); + }); + + describe('column menu', () => { + it('should add a "Group by {field}" menu item on ungrouped columns when coLDef.canBeGrouped is not defined', () => { + render( + , + ); + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const menuItem = screen.queryByRole('menuitem', { name: 'Group by category1' }); + fireEvent.click(menuItem); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category1']); + }); + + it('should not add a "Group by {field}" menu item on ungrouped columns when coLDef.canBeGrouped = false', () => { + render( + , + ); + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + expect(screen.queryByRole('menuitem', { name: 'Group by category1' })).to.equal(null); + }); + + it('should add a "Stop grouping by {field}" menu item on grouped column', () => { + render( + , + ); + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const menuItem = screen.queryByRole('menuitem', { name: 'Stop grouping by category1' }); + fireEvent.click(menuItem); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + }); + + it('should add a "Stop grouping by {field} menu item on each grouping column when prop.groupingColumnMode = "multiple"', () => { + render( + , + ); + + apiRef.current.showColumnMenu('__row_group_by_columns_group_category1__'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const menuItemCategory1 = screen.queryByRole('menuitem', { + name: 'Stop grouping by category1', + }); + fireEvent.click(menuItemCategory1); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2']); + + apiRef.current.hideColumnMenu(); + clock.runToLast(); + expect(screen.queryByRole('menu')).to.equal(null); + + apiRef.current.showColumnMenu('__row_group_by_columns_group_category2__'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const menuItemCategory2 = screen.queryByRole('menuitem', { + name: 'Stop grouping by category2', + }); + fireEvent.click(menuItemCategory2); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + }); + + it('should add a "Stop grouping {field} menu item for each grouping criteria on the grouping column when prop.groupingColumnMode = "single"', () => { + render( + , + ); + + apiRef.current.showColumnMenu('__row_group_by_columns_group__'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + const menuItemCategory1 = screen.queryByRole('menuitem', { + name: 'Stop grouping by category1', + }); + fireEvent.click(menuItemCategory1); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2']); + const menuItemCategory2 = screen.queryByRole('menuitem', { + name: 'Stop grouping by category2', + }); + fireEvent.click(menuItemCategory2); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + }); + + it('should use the colDef.headerName property for grouping menu item label', () => { + render( + , + ); + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + expect(screen.queryByRole('menuitem', { name: 'Group by Category 1' })).not.to.equal(null); + }); + + it('should use the colDef.headerName property for ungrouping menu item label', () => { + render( + , + ); + apiRef.current.showColumnMenu('category1'); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + expect(screen.queryByRole('menuitem', { name: 'Stop grouping by Category 1' })).not.to.equal( + null, + ); + }); + }); + + describe('sorting', () => { + describe('props: groupingColumnMode = "single"', () => { + it('should use the top level grouping criteria for sorting if mainGroupingCriteria and leafField are not defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat B (2)', + 'Cat 2 (1)', + '', + 'Cat 1 (1)', + '', + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + ]); + }); + + it('should use the column grouping criteria for sorting if mainGroupingCriteria is one of the grouping criteria and leaf field is defined', () => { + render( + , + ); + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 2 (2)', + '1', + '2', + 'Cat 1 (1)', + '0', + 'Cat B (2)', + 'Cat 2 (1)', + '3', + 'Cat 1 (1)', + '4', + ]); + }); + + it('should use the leaf field for sorting if mainGroupingCriteria is not defined and leaf field is defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '0', + 'Cat 2 (2)', + '2', + '1', + 'Cat B (2)', + 'Cat 2 (1)', + '3', + 'Cat 1 (1)', + '4', + ]); + }); + + it('should use the leaf field for sorting if mainGroupingCriteria is not one of the grouping criteria and leaf field is defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '0', + 'Cat 2 (2)', + '2', + '1', + 'Cat B (2)', + 'Cat 2 (1)', + '3', + 'Cat 1 (1)', + '4', + ]); + }); + + it('should sort unbalanced grouped by index of the groupingField in the model when sorting by a grouping criteria', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat B (2)', + '2', + '3', + 'Cat A (2)', + '0', + '1', + '4', + '5', + ]); + }); + + it('should sort unbalanced grouped by index of the groupingField in the model when sorting by leaves', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (2)', + '1', + '0', + 'Cat B (2)', + '3', + '2', + '5', + '4', + ]); + }); + }); + + describe('props: groupingColumnMode = "multiple"', () => { + it('should use the column grouping criteria for sorting if mainGroupingCriteria and leafField are not defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal(['Cat B (2)', '', '', 'Cat A (3)', '', '', '']); + }); + + it('should use the column grouping criteria for sorting if mainGroupingCriteria matches the column grouping criteria and leaf field is defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat B (2)', + '3', + '4', + 'Cat A (3)', + '0', + '1', + '2', + ]); + }); + + it('should use the leaf field for sorting if mainGroupingCriteria is not defined and leaf field is defined', () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '2', + '1', + '0', + 'Cat B (2)', + '4', + '3', + ]); + }); + + it("should use the leaf field for sorting if mainGroupingCriteria doesn't match the column grouping criteria and leaf field is defined", () => { + render( + , + ); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + '2', + '1', + '0', + 'Cat B (2)', + '4', + '3', + ]); + }); + }); + }); + + describe('filtering', () => { + clock.withFakeTimers(); + + describe('props: groupingColumnMode = "single"', () => { + it('should use the top level grouping criteria for filtering if mainGroupingCriteria and leafField are not defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('textbox', { name: 'Value' }), { + target: { value: 'Cat A' }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (3)', + 'Cat 1 (1)', + '', + 'Cat 2 (2)', + '', + '', + ]); + }); + + it('should use the column grouping criteria for filtering if mainGroupingCriteria is one of the grouping criteria and leaf field is defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('textbox', { name: 'Value' }), { + target: { value: 'Cat 1' }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal([ + 'Cat A (1)', + 'Cat 1 (1)', + '0', + 'Cat B (1)', + 'Cat 1 (1)', + '4', + ]); + }); + + it('should use the leaf field for filtering if mainGroupingCriteria is not defined and leaf field is defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('combobox', { name: 'Operators' }), { + target: { value: '>' }, + }); + fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), { + target: { value: 2 }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat B (2)', 'Cat 2 (1)', '3', 'Cat 1 (1)', '4']); + }); + + it('should use the leaf field for filtering if mainGroupingCriteria is not one of the grouping criteria and leaf field is defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('combobox', { name: 'Operators' }), { + target: { value: '>' }, + }); + fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), { + target: { value: 2 }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat B (2)', 'Cat 2 (1)', '3', 'Cat 1 (1)', '4']); + }); + + it('should not filter the groups when filtering with an item that is not on the grouping column', () => { + render( + { + it('should use the column grouping criteria for filtering if mainGroupingCriteria and leafField are not defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('textbox', { name: 'Value' }), { + target: { value: 'Cat A' }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '']); + expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2']); + }); + + it('should use the column grouping criteria for filtering if mainGroupingCriteria matches the column grouping criteria and leaf field is defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('textbox', { name: 'Value' }), { + target: { value: 'Cat A' }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '0', '1', '2']); + }); + + it('should use the leaf field for filtering if mainGroupingCriteria is not defined and leaf field is defined', () => { + render( + , + ); + + fireEvent.change(screen.getByRole('combobox', { name: 'Operators' }), { + target: { value: '>' }, + }); + fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), { + target: { value: 2 }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat B (2)', '3', '4']); + }); + + it("should use the leaf field for filtering if mainGroupingCriteria doesn't match the column grouping criteria and leaf field is defined", () => { + render( + , + ); + + fireEvent.change(screen.getByRole('combobox', { name: 'Operators' }), { + target: { value: '>' }, + }); + fireEvent.change(screen.getByRole('spinbutton', { name: 'Value' }), { + target: { value: 2 }, + }); + clock.tick(500); + + expect(getColumnValues(0)).to.deep.equal(['Cat B (2)', '3', '4']); + }); + + it('should not filter the groups when filtering with an item that is not on the grouping column', () => { + render( + { + render( + , + ); + + // "Cat A" is testing against the "__row_group_by_columns_group_category1__" filter item, but "Cat 1" and "Cat 2" are not + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', '', '']); + expect(getColumnValues(1)).to.deep.equal(['', 'Cat 1 (1)', '', 'Cat 2 (2)', '', '']); + }); + }); + }); + + describe('apiRef: addGroupingCriteria', () => { + it('should add grouping criteria to model', () => { + render(); + apiRef.current.addGroupingCriteria('category2'); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category1', 'category2']); + }); + + it('should add grouping criteria to model at the right position', () => { + render(); + apiRef.current.addGroupingCriteria('category2', 0); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2', 'category1']); + }); + }); + + describe('apiRef: removeGroupingCriteria', () => { + it('should remove field from model', () => { + render(); + apiRef.current.removeGroupingCriteria('category1'); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + }); + }); + + describe('apiRef: setGroupingCriteriaIndex', () => { + it('should change the grouping criteria order', () => { + render(); + apiRef.current.setGroupingCriteriaIndex('category1', 1); + expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2', 'category1']); + }); + }); +}); diff --git a/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx b/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx index 7444bd5cfa534..f6496476ef669 100644 --- a/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx +++ b/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx @@ -27,11 +27,13 @@ import { useGridScroll } from '../../_modules_/grid/hooks/features/scroll/useGri import { useGridEvents } from '../../_modules_/grid/hooks/features/events/useGridEvents'; import { useGridDimensions } from '../../_modules_/grid/hooks/features/dimensions/useGridDimensions'; import { useGridTreeData } from '../../_modules_/grid/hooks/features/treeData/useGridTreeData'; +import { useGridGroupingColumns } from '../../_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns'; import { useGridColumnPinning } from '../../_modules_/grid/hooks/features/columnPinning/useGridColumnPinning'; export const useDataGridProComponent = (apiRef: GridApiRef, props: GridComponentProps) => { useGridInitialization(apiRef, props); useGridTreeData(apiRef, props); + useGridGroupingColumns(apiRef, props); useGridSelection(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); diff --git a/packages/grid/x-data-grid/src/DataGridProps.ts b/packages/grid/x-data-grid/src/DataGridProps.ts index 620e2ea53a386..8a25b4095c657 100644 --- a/packages/grid/x-data-grid/src/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/DataGridProps.ts @@ -17,6 +17,7 @@ export type DataGridProps = Omit< | 'disableChildrenFiltering' | 'disableChildrenSorting' | 'disableColumnPinning' + | 'disableGroupingColumns' | 'throttleRowsMs' | 'hideFooterRowCount' | 'options' @@ -28,7 +29,12 @@ export type DataGridProps = Omit< | 'getTreeDataPath' | 'groupingColDef' | 'defaultGroupingExpansionDepth' + | 'groupingColumnMode' + | 'groupingColumnsModel' + | 'onGroupingColumnsModelChange' | 'signature' + // TODO: Remove if we have an experimental feature concerning the DataGrid and override the property to only expose the experimental features of the DataGrid. + | 'experimentalFeatures' > & { pagination?: true; }; diff --git a/packages/grid/x-data-grid/src/useDataGridProps.ts b/packages/grid/x-data-grid/src/useDataGridProps.ts index 5f16fc82ce9a0..3cd9d1d594af6 100644 --- a/packages/grid/x-data-grid/src/useDataGridProps.ts +++ b/packages/grid/x-data-grid/src/useDataGridProps.ts @@ -19,6 +19,7 @@ const FORCED_PROPS: { [key in ForcedPropsKey]-?: GridInputComponentProps[key] } disableChildrenFiltering: undefined, disableChildrenSorting: undefined, disableColumnPinning: undefined, + disableGroupingColumns: undefined, getTreeDataPath: undefined, groupingColDef: undefined, throttleRowsMs: undefined, @@ -31,6 +32,10 @@ const FORCED_PROPS: { [key in ForcedPropsKey]-?: GridInputComponentProps[key] } onPinnedColumnsChange: undefined, defaultGroupingExpansionDepth: undefined, treeData: undefined, + groupingColumnMode: undefined, + groupingColumnsModel: undefined, + onGroupingColumnsModelChange: undefined, + experimentalFeatures: undefined, signature: 'DataGrid', }; diff --git a/scripts/exportsSnapshot.json b/scripts/exportsSnapshot.json index 7a960561812e5..66abeb25c9cd1 100644 --- a/scripts/exportsSnapshot.json +++ b/scripts/exportsSnapshot.json @@ -204,6 +204,13 @@ { "name": "GridFooterPlaceholder", "kind": "Function" }, { "name": "GridGroupingColDefOverride", "kind": "Interface" }, { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, + { "name": "GridGroupingColumnsApi", "kind": "Interface" }, + { "name": "GridGroupingColumnsInitialState", "kind": "Interface" }, + { "name": "GridGroupingColumnsModel", "kind": "TypeAlias" }, + { "name": "gridGroupingColumnsModelSelector", "kind": "Variable" }, + { "name": "gridGroupingColumnsSanitizedModelSelector", "kind": "Variable" }, + { "name": "GridGroupingColumnsState", "kind": "Interface" }, + { "name": "gridGroupingColumnsStateSelector", "kind": "Variable" }, { "name": "GridHeader", "kind": "Variable" }, { "name": "GridHeaderCheckbox", "kind": "ExportSpecifier" }, { "name": "GridHeaderPlaceholder", "kind": "Function" }, @@ -212,6 +219,7 @@ { "name": "GridInitialState", "kind": "Interface" }, { "name": "GridInputComponentProps", "kind": "Interface" }, { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, + { "name": "GridKeyGetterParams", "kind": "Interface" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, From 48545cd28c806a936ed789c491e449312927cc60 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 14 Dec 2021 09:37:03 +0100 Subject: [PATCH 02/33] Code review: stop hiding grouped column for 2 most basic examples --- .../group-pivot/GroupingColumnsControlled.js | 42 +-------------- .../group-pivot/GroupingColumnsControlled.tsx | 47 ---------------- .../GroupingColumnsControlled.tsx.preview | 1 - .../GroupingColumnsInitialState.js | 42 +-------------- .../GroupingColumnsInitialState.tsx | 53 +------------------ .../GroupingColumnsInitialState.tsx.preview | 1 - 6 files changed, 3 insertions(+), 183 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js index fa8f6d017ffbc..2995e9fb95e11 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js @@ -1,42 +1,9 @@ import * as React from 'react'; -import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { DataGridPro, useGridApiRef } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - - prevModel.current = initialModel; - }, - ); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - export default function GroupingColumnsControlled() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -45,18 +12,11 @@ export default function GroupingColumnsControlled() { INITIAL_GROUPING_COLUMN_MODEL, ); - const columns = useKeepGroupingColumnsHidden( - apiRef, - data.columns, - INITIAL_GROUPING_COLUMN_MODEL, - ); - return (
setGroupingColumnsModel(model)} experimentalFeatures={{ diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx index b8eaed92f92b6..0ab148b3f1075 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx @@ -1,9 +1,6 @@ import * as React from 'react'; import { DataGridPro, - GridApiRef, - GridColumns, - GridEvents, GridGroupingColumnsModel, useGridApiRef, } from '@mui/x-data-grid-pro'; @@ -11,43 +8,6 @@ import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -const useKeepGroupingColumnsHidden = ( - apiRef: GridApiRef, - columns: GridColumns, - initialModel: GridGroupingColumnsModel, - leafField?: string, -) => { - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - export default function GroupingColumnsControlled() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -55,18 +15,11 @@ export default function GroupingColumnsControlled() { const [groupingColumnsModel, setGroupingColumnsModel] = React.useState(INITIAL_GROUPING_COLUMN_MODEL); - const columns = useKeepGroupingColumnsHidden( - apiRef, - data.columns, - INITIAL_GROUPING_COLUMN_MODEL, - ); - return (
setGroupingColumnsModel(model)} experimentalFeatures={{ diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview index 52b1567caaefa..d26e5a9b16bd0 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview @@ -1,7 +1,6 @@ setGroupingColumnsModel(model)} experimentalFeatures={{ diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js index c430127e89ae6..f820cc24e3833 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js +++ b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js @@ -1,58 +1,18 @@ import * as React from 'react'; -import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { DataGridPro, useGridApiRef } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - - prevModel.current = initialModel; - }, - ); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - export default function GroupingColumnsInitialState() { const data = useMovieData(); const apiRef = useGridApiRef(); - const columns = useKeepGroupingColumnsHidden( - apiRef, - data.columns, - INITIAL_GROUPING_COLUMN_MODEL, - ); - return (
{ - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - export default function GroupingColumnsInitialState() { const data = useMovieData(); const apiRef = useGridApiRef(); - const columns = useKeepGroupingColumnsHidden( - apiRef, - data.columns, - INITIAL_GROUPING_COLUMN_MODEL, - ); - return (
Date: Wed, 15 Dec 2021 15:50:24 +0100 Subject: [PATCH 03/33] Rename feature 'Grouping columns' => 'Row grouping' --- .../api-docs/data-grid/data-grid-pro.json | 16 +- docs/pages/api-docs/data-grid/grid-api.md | 186 +++++----- ...ns-api.json => grid-row-grouping-api.json} | 22 +- .../api/buildInterfacesDocumentation.ts | 2 +- .../components/data-grid/events/events.json | 12 +- .../group-pivot/GroupingColumnsApiNoSnap.js | 7 - .../GroupingColumnsControlled.tsx.preview | 9 - ...pingColumnsMultipleGroupingCol.tsx.preview | 14 - .../group-pivot/RowGroupingApiNoSnap.js | 7 + ...ed.js => RowGroupingColDefCanBeGrouped.js} | 31 +- ....tsx => RowGroupingColDefCanBeGrouped.tsx} | 35 +- ...RowGroupingColDefCanBeGrouped.tsx.preview} | 4 +- ...Controlled.js => RowGroupingControlled.js} | 10 +- ...ntrolled.tsx => RowGroupingControlled.tsx} | 14 +- .../RowGroupingControlled.tsx.preview | 9 + ...owGroupingCustomGroupingColDefCallback.js} | 45 ++- ...wGroupingCustomGroupingColDefCallback.tsx} | 49 ++- ... RowGroupingCustomGroupingColDefObject.js} | 31 +- ...RowGroupingCustomGroupingColDefObject.tsx} | 35 +- ...js => RowGroupingDefaultExpansionDepth.js} | 31 +- ...x => RowGroupingDefaultExpansionDepth.tsx} | 35 +- ...GroupingDefaultExpansionDepth.tsx.preview} | 4 +- ...umnsDisabled.js => RowGroupingDisabled.js} | 6 +- ...nsDisabled.tsx => RowGroupingDisabled.tsx} | 6 +- ...review => RowGroupingDisabled.tsx.preview} | 4 +- ...llExample.js => RowGroupingFullExample.js} | 31 +- ...Example.tsx => RowGroupingFullExample.tsx} | 35 +- ...t.js => RowGroupingHideDescendantCount.js} | 31 +- ...tsx => RowGroupingHideDescendantCount.tsx} | 35 +- ...ialState.js => RowGroupingInitialState.js} | 6 +- ...lState.tsx => RowGroupingInitialState.tsx} | 6 +- ...ew => RowGroupingInitialState.tsx.preview} | 4 +- ...nsKeyGetter.js => RowGroupingKeyGetter.js} | 31 +- ...KeyGetter.tsx => RowGroupingKeyGetter.tsx} | 35 +- ...eview => RowGroupingKeyGetter.tsx.preview} | 4 +- ....js => RowGroupingKeyGetterValueGetter.js} | 31 +- ...sx => RowGroupingKeyGetterValueGetter.tsx} | 35 +- ...wGroupingKeyGetterValueGetter.tsx.preview} | 4 +- ...thValue.js => RowGroupingLeafWithValue.js} | 31 +- ...Value.tsx => RowGroupingLeafWithValue.tsx} | 35 +- ...w => RowGroupingLeafWithValue.tsx.preview} | 4 +- ...l.js => RowGroupingMultipleGroupingCol.js} | 33 +- ...tsx => RowGroupingMultipleGroupingCol.tsx} | 37 +- ...owGroupingMultipleGroupingCol.tsx.preview} | 6 +- ...js => RowGroupingRowsWithMissingGroups.js} | 31 +- ...x => RowGroupingRowsWithMissingGroups.tsx} | 35 +- ...GroupingRowsWithMissingGroups.tsx.preview} | 4 +- ....js => RowGroupingSetChildrenExpansion.js} | 31 +- ...sx => RowGroupingSetChildrenExpansion.tsx} | 35 +- ...Col.js => RowGroupingSingleGroupingCol.js} | 33 +- ...l.tsx => RowGroupingSingleGroupingCol.tsx} | 37 +- .../RowGroupingSingleGroupingCol.tsx.preview | 14 + ...wGroupingSortingMultipleGroupingColDef.js} | 33 +- ...GroupingSortingMultipleGroupingColDef.tsx} | 37 +- ...RowGroupingSortingSingleGroupingColDef.js} | 33 +- ...owGroupingSortingSingleGroupingColDef.tsx} | 37 +- .../data-grid/group-pivot/group-pivot.md | 62 ++-- .../api-docs/data-grid/data-grid-pro-pt.json | 8 +- .../api-docs/data-grid/data-grid-pro-zh.json | 8 +- .../api-docs/data-grid/data-grid-pro.json | 8 +- .../grid/_modules_/grid/GridComponentProps.ts | 11 +- .../cell/GridGroupingColumnLeafCell.tsx | 2 +- .../cell/GridGroupingCriteriaCell.tsx | 2 +- ...Items.tsx => GridRowGroupingMenuItems.tsx} | 22 +- .../gridGroupingColumnsInterfaces.ts | 37 -- .../gridGroupingColumnsSelector.ts | 17 - .../hooks/features/groupingColumns/index.ts | 2 - .../_modules_/grid/hooks/features/index.ts | 2 +- .../createGroupingColDef.tsx | 20 +- .../rowGrouping/gridRowGroupingInterfaces.ts | 37 ++ .../rowGrouping/gridRowGroupingSelector.ts | 17 + .../gridRowGroupingUtils.ts} | 0 .../grid/hooks/features/rowGrouping/index.ts | 2 + .../useGridRowGrouping.tsx} | 140 ++++---- .../grid/hooks/utils/useGridProcessedProps.ts | 3 +- .../grid/_modules_/grid/models/api/gridApi.ts | 4 +- .../grid/models/colDef/gridColDef.ts | 2 +- .../grid/models/events/gridEventLookup.ts | 4 +- .../grid/models/events/gridEvents.ts | 4 +- .../_modules_/grid/models/gridOptions.tsx | 10 +- .../grid/_modules_/grid/models/gridState.ts | 10 +- .../grid/x-data-grid-pro/src/DataGridPro.tsx | 44 +-- ...t.tsx => rowGrouping.DataGridPro.test.tsx} | 334 +++++++++--------- .../src/useDataGridProComponent.tsx | 4 +- .../grid/x-data-grid/src/DataGridProps.ts | 8 +- .../grid/x-data-grid/src/useDataGridProps.ts | 8 +- scripts/x-data-grid-pro.exports.json | 14 +- scripts/x-data-grid.exports.json | 14 +- 88 files changed, 1087 insertions(+), 1191 deletions(-) rename docs/pages/api-docs/data-grid/{grid-grouping-columns-api.json => grid-row-grouping-api.json} (54%) delete mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js delete mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview delete mode 100644 docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingApiNoSnap.js rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsColDefCanBeGrouped.js => RowGroupingColDefCanBeGrouped.js} (69%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsColDefCanBeGrouped.tsx => RowGroupingColDefCanBeGrouped.tsx} (68%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsColDefCanBeGrouped.tsx.preview => RowGroupingColDefCanBeGrouped.tsx.preview} (81%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsControlled.js => RowGroupingControlled.js} (63%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsControlled.tsx => RowGroupingControlled.tsx} (55%) create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx.preview rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsCustomGroupingColDefCallback.js => RowGroupingCustomGroupingColDefCallback.js} (62%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsCustomGroupingColDefCallback.tsx => RowGroupingCustomGroupingColDefCallback.tsx} (61%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsCustomGroupingColDefObject.js => RowGroupingCustomGroupingColDefObject.js} (67%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsCustomGroupingColDefObject.tsx => RowGroupingCustomGroupingColDefObject.tsx} (66%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDefaultExpansionDepth.js => RowGroupingDefaultExpansionDepth.js} (67%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDefaultExpansionDepth.tsx => RowGroupingDefaultExpansionDepth.tsx} (65%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDefaultExpansionDepth.tsx.preview => RowGroupingDefaultExpansionDepth.tsx.preview} (82%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDisabled.js => RowGroupingDisabled.js} (76%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDisabled.tsx => RowGroupingDisabled.tsx} (76%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsDisabled.tsx.preview => RowGroupingDisabled.tsx.preview} (61%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsFullExample.js => RowGroupingFullExample.js} (71%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsFullExample.tsx => RowGroupingFullExample.tsx} (69%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsHideDescendantCount.js => RowGroupingHideDescendantCount.js} (67%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsHideDescendantCount.tsx => RowGroupingHideDescendantCount.tsx} (66%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsInitialState.js => RowGroupingInitialState.js} (83%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsInitialState.tsx => RowGroupingInitialState.tsx} (83%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsInitialState.tsx.preview => RowGroupingInitialState.tsx.preview} (77%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetter.js => RowGroupingKeyGetter.js} (71%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetter.tsx => RowGroupingKeyGetter.tsx} (71%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetterValueGetter.tsx.preview => RowGroupingKeyGetter.tsx.preview} (77%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetterValueGetter.js => RowGroupingKeyGetterValueGetter.js} (74%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetterValueGetter.tsx => RowGroupingKeyGetterValueGetter.tsx} (74%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsKeyGetter.tsx.preview => RowGroupingKeyGetterValueGetter.tsx.preview} (77%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsLeafWithValue.js => RowGroupingLeafWithValue.js} (67%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsLeafWithValue.tsx => RowGroupingLeafWithValue.tsx} (65%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsLeafWithValue.tsx.preview => RowGroupingLeafWithValue.tsx.preview} (80%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSingleGroupingCol.js => RowGroupingMultipleGroupingCol.js} (64%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSingleGroupingCol.tsx => RowGroupingMultipleGroupingCol.tsx} (63%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSingleGroupingCol.tsx.preview => RowGroupingMultipleGroupingCol.tsx.preview} (68%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsRowsWithMissingGroups.js => RowGroupingRowsWithMissingGroups.js} (66%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsRowsWithMissingGroups.tsx => RowGroupingRowsWithMissingGroups.tsx} (65%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsRowsWithMissingGroups.tsx.preview => RowGroupingRowsWithMissingGroups.tsx.preview} (79%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSetChildrenExpansion.js => RowGroupingSetChildrenExpansion.js} (74%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSetChildrenExpansion.tsx => RowGroupingSetChildrenExpansion.tsx} (73%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsMultipleGroupingCol.js => RowGroupingSingleGroupingCol.js} (64%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsMultipleGroupingCol.tsx => RowGroupingSingleGroupingCol.tsx} (63%) create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx.preview rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSortingMultipleGroupingColDef.js => RowGroupingSortingMultipleGroupingColDef.js} (69%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSortingMultipleGroupingColDef.tsx => RowGroupingSortingMultipleGroupingColDef.tsx} (67%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSortingSingleGroupingColDef.js => RowGroupingSortingSingleGroupingColDef.js} (79%) rename docs/src/pages/components/data-grid/group-pivot/{GroupingColumnsSortingSingleGroupingColDef.tsx => RowGroupingSortingSingleGroupingColDef.tsx} (78%) rename packages/grid/_modules_/grid/components/menu/columnMenu/{GridGroupingColumnsMenuItems.tsx => GridRowGroupingMenuItems.tsx} (79%) delete mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts delete mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts delete mode 100644 packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts rename packages/grid/_modules_/grid/hooks/features/{groupingColumns => rowGrouping}/createGroupingColDef.tsx (95%) create mode 100644 packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts create mode 100644 packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts rename packages/grid/_modules_/grid/hooks/features/{groupingColumns/gridGroupingColumnsUtils.ts => rowGrouping/gridRowGroupingUtils.ts} (100%) create mode 100644 packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts rename packages/grid/_modules_/grid/hooks/features/{groupingColumns/useGridGroupingColumns.tsx => rowGrouping/useGridRowGrouping.tsx} (75%) rename packages/grid/x-data-grid-pro/src/tests/{groupingColumns.DataGridPro.test.tsx => rowGrouping.DataGridPro.test.tsx} (82%) diff --git a/docs/pages/api-docs/data-grid/data-grid-pro.json b/docs/pages/api-docs/data-grid/data-grid-pro.json index f565e14444d06..17fc66a1f81a2 100644 --- a/docs/pages/api-docs/data-grid/data-grid-pro.json +++ b/docs/pages/api-docs/data-grid/data-grid-pro.json @@ -42,10 +42,10 @@ "disableColumnSelector": { "type": { "name": "bool" } }, "disableDensitySelector": { "type": { "name": "bool" } }, "disableExtendRowFullWidth": { "type": { "name": "bool" } }, - "disableGroupingColumns": { "type": { "name": "bool" } }, "disableMultipleColumnsFiltering": { "type": { "name": "bool" } }, "disableMultipleColumnsSorting": { "type": { "name": "bool" } }, "disableMultipleSelection": { "type": { "name": "bool" } }, + "disableRowGrouping": { "type": { "name": "bool" } }, "disableSelectionOnClick": { "type": { "name": "bool" } }, "disableVirtualization": { "type": { "name": "bool" } }, "editMode": { @@ -55,7 +55,7 @@ "editRowsModel": { "type": { "name": "object" } }, "error": { "type": { "name": "any" } }, "experimentalFeatures": { - "type": { "name": "shape", "description": "{ groupingColumns?: bool }" } + "type": { "name": "shape", "description": "{ rowGrouping?: bool }" } }, "filterMode": { "type": { "name": "custom", "description": "'client'
| 'server'" }, @@ -72,11 +72,6 @@ "getRowId": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, - "groupingColumnMode": { - "type": { "name": "enum", "description": "'multiple'
| 'single'" }, - "default": "'single'" - }, - "groupingColumnsModel": { "type": { "name": "arrayOf", "description": "Array<string>" } }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, @@ -130,7 +125,6 @@ "onEditRowsModelChange": { "type": { "name": "func" } }, "onError": { "type": { "name": "func" } }, "onFilterModelChange": { "type": { "name": "func" } }, - "onGroupingColumnsModelChange": { "type": { "name": "func" } }, "onPageChange": { "type": { "name": "func" } }, "onPageSizeChange": { "type": { "name": "func" } }, "onPinnedColumnsChange": { "type": { "name": "func" } }, @@ -140,6 +134,7 @@ "onRowEditCommit": { "type": { "name": "func" } }, "onRowEditStart": { "type": { "name": "func" } }, "onRowEditStop": { "type": { "name": "func" } }, + "onRowGroupingModelChange": { "type": { "name": "func" } }, "onRowsScrollEnd": { "type": { "name": "func" } }, "onSelectionModelChange": { "type": { "name": "func" } }, "onSortModelChange": { "type": { "name": "func" } }, @@ -159,6 +154,11 @@ }, "rowBuffer": { "type": { "name": "number" }, "default": "3" }, "rowCount": { "type": { "name": "number" } }, + "rowGroupingColumnMode": { + "type": { "name": "enum", "description": "'multiple'
| 'single'" }, + "default": "'single'" + }, + "rowGroupingModel": { "type": { "name": "arrayOf", "description": "Array<string>" } }, "rowHeight": { "type": { "name": "number" }, "default": "52" }, "rowsPerPageOptions": { "type": { "name": "arrayOf", "description": "Array<number>" }, diff --git a/docs/pages/api-docs/data-grid/grid-api.md b/docs/pages/api-docs/data-grid/grid-api.md index 0b4554a096734..d5ebf3047a6d3 100644 --- a/docs/pages/api-docs/data-grid/grid-api.md +++ b/docs/pages/api-docs/data-grid/grid-api.md @@ -10,96 +10,96 @@ import { GridApi } from '@mui/x-data-grid-pro'; ## Properties -| Name | Type | Description | -| :------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| addGroupingCriteria | (groupingCriteriaField: string, groupingIndex?: number) => void | Add the field to the groupingColumnsModel. | -| applySorting | () => void | Applies the current sort model to the rows. | -| commitCellChange | (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the field at the given id with the value stored in the edit row model. | -| commitRowChange | (id: GridRowId, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the row at the given id with the values stored in the edit row model. | -| deleteFilterItem | (item: GridFilterItem) => void | Deletes a GridFilterItem. | -| exportDataAsCsv | (options?: GridCsvExportOptions) => void | Downloads and exports a CSV of the grid's data. | -| exportDataAsPrint | (options?: GridPrintExportOptions) => void | Print the grid's data. | -| forceUpdate | () => void | Forces the grid to rerender. It's often used after a state update. | -| getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/api/data-grid/grid-col-def/) containing all the column definitions. | -| getAllRowIds | () => GridRowId[] | Gets the list of row ids. | -| getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | -| getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | -| getCellParams | (id: GridRowId, field: string) => GridCellParams | Gets the [GridCellParams](/api/data-grid/grid-cell-params/) object that is passed as argument in events. | -| getCellValue | (id: GridRowId, field: string) => GridCellValue | Gets the value of a cell at the given `id` and `field`. | -| getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/api/data-grid/grid-col-def/) for the given `field`. | -| getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | -| getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | -| getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | -| getColumnPosition | (field: string) => number | Returns the left-position of a column relative to the inner border of the grid. | -| getColumnsMeta | () => GridColumnsMeta | Returns the GridColumnsMeta for each column. | -| getDataAsCsv | (options?: GridCsvExportOptions) => string | Returns the grid data as a CSV string.
This method is used internally by `exportDataAsCsv`. | -| getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | -| getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | -| getPinnedColumns | () => GridPinnedColumns | Returns which columns are pinned. | -| getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | -| getRow | (id: GridRowId) => GridRowModel \| null | Gets the row data with a given id. | -| getRowElement | (id: GridRowId) => HTMLDivElement \| null | Gets the underlying DOM element for a row at the given `id`. | -| getRowIdFromRowIndex | (index: number) => GridRowId | Gets the `GridRowId` of a row at a specific index.
The index is based on the sorted but unfiltered row list. | -| getRowIndex | (id: GridRowId) => number | Gets the row index of a row with a given id.
The index is based on the sorted but unfiltered row list. | -| getRowMode | (id: GridRowId) => GridRowMode | Gets the mode of a row. | -| getRowModels | () => Map<GridRowId, GridRowModel> | Gets the full set of rows as Map<GridRowId, GridRowModel>. | -| getRowNode | (id: GridRowId) => GridRowTreeNodeConfig \| null | Gets the row node from the internal tree structure. | -| getRowParams | (id: GridRowId) => GridRowParams | Gets the [GridRowParams](/api/data-grid/grid-row-params/) object that is passed as argument in events. | -| getRowsCount | () => number | Gets the total number of rows in the grid. | -| getScrollPosition | () => GridScrollParams | Returns the current scroll position. | -| getSelectedRows | () => Map<GridRowId, GridRowModel> | Returns an array of the selected rows. | -| getSortedRowIds | () => GridRowId[] | Returns all row ids sorted according to the active sort model. | -| getSortedRows | () => GridRowModel[] | Returns all rows sorted according to the active sort model. | -| getSortModel | () => GridSortModel | Returns the sort model currently applied to the grid. | -| getVisibleColumns | () => GridStateColDef[] | Returns the currently visible columns. | -| getVisibleRowModels | () => Map<GridRowId, GridRowModel> | Returns a sorted `Map` containing only the visible rows. | -| hideColumnMenu | () => void | Hides the column menu that is open. | -| hideFilterPanel | () => void | Hides the filter panel. | -| hidePreferences | () => void | Hides the preferences panel. | -| isCellEditable | (params: GridCellParams) => boolean | Controls if a cell is editable. | -| isColumnPinned | (field: string) => GridPinnedPosition \| false | Returns which side a column is pinned to. | -| isRowSelected | (id: GridRowId) => boolean | Determines if a row is selected or not. | -| pinColumn | (field: string, side: GridPinnedPosition) => void | Pins a column to the left or right side of the grid. | -| publishEvent | GridEventPublisher | Emits an event. | -| removeGroupingCriteria | (groupingCriteriaField: string) => void | Remove the field from to groupingColumnsModel. | -| resize | () => void | Triggers a resize of the component and recalculation of width and height. | -| scroll | (params: Partial<GridScrollParams>) => void | Triggers the viewport to scroll to the given positions (in pixels). | -| scrollToIndexes | (params: Partial<GridCellIndexCoordinates>) => boolean | Triggers the viewport to scroll to the cell at indexes given by `params`.
Returns `true` if the grid had to scroll to reach the target. | -| selectRow | (id: GridRowId, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of a row. | -| selectRowRange | (range: { startId: GridRowId; endId: GridRowId }, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of all the selectable rows in a range. | -| selectRows | (ids: GridRowId[], isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of multiple rows. | -| setCellFocus | (id: GridRowId, field: string) => void | Sets the focus to the cell at the given `id` and `field`. | -| setCellMode | (id: GridRowId, field: string, mode: GridCellMode) => void | Sets the mode of a cell. | -| setColumnHeaderFocus | (field: string, event?: MuiBaseEvent) => void | Sets the focus to the column header at the given `field`. | -| setColumnIndex | (field: string, targetIndexPosition: number) => void | Moves a column from its original position to the position given by `targetIndexPosition`. | -| setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | -| setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | -| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number) => void | Sets the density of the grid. | -| setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | -| setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | -| setFilterLinkOperator | (operator: GridLinkOperator) => void | Changes the GridLinkOperator used to connect the filters. | -| setFilterModel | (model: GridFilterModel) => void | Sets the filter model to the one given by `model`. | -| setGroupingColumnsModel | (model: GridGroupingColumnsModel) => void | Sets the columns to use as grouping criteria. | -| setGroupingCriteriaIndex | (groupingCriteriaField: string, groupingIndex: number) => void | Sets the grouping index of a grouping criteria. | -| setPage | (page: number) => void | Sets the displayed page to the value given by `page`. | -| setPageSize | (pageSize: number) => void | Sets the number of displayed rows to the value given by `pageSize`. | -| setPinnedColumns | (pinnedColumns: GridPinnedColumns) => void | Changes the pinned columns. | -| setRowChildrenExpansion | (id: GridRowId, isExpanded: boolean) => void | Expand or collapse a row children. | -| setRowMode | (id: GridRowId, mode: GridRowMode) => void | Sets the mode of a row. | -| setRows | (rows: GridRowModel[]) => void | Sets a new set of rows. | -| setSelectionModel | (rowIds: GridRowId[]) => void | Updates the selected rows to be those passed to the `rowIds` argument.
Any row already selected will be unselected. | -| setSortModel | (model: GridSortModel) => void | Updates the sort model and triggers the sorting of rows. | -| setState | (state: GridState \| ((previousState: GridState) => GridState)) => boolean | Sets the whole state of the grid. | -| showColumnMenu | (field: string) => void | Display the column menu under the `field` column. | -| showError | (props: any) => void | Displays the error overlay component. | -| showFilterPanel | (targetColumnField?: string) => void | Shows the filter panel. If `targetColumnField` is given, a filter for this field is also added. | -| showPreferences | (newValue: GridPreferencePanelsValue) => void | Displays the preferences panel. The `newValue` argument controls the content of the panel. | -| sortColumn | (column: GridColDef, direction?: GridSortDirection, allowMultipleSorting?: boolean) => void | Sorts a column. | -| state | GridState | Property that contains the whole state of the grid. | -| subscribeEvent | <E extends GridEventsStr>(event: E, handler: GridEventListener<E>, options?: EventListenerOptions) => () => void | Registers a handler for an event. | -| toggleColumnMenu | (field: string) => void | Toggles the column menu under the `field` column. | -| unpinColumn | (field: string) => void | Unpins a column. | -| updateColumn | (col: GridColDef) => void | Updates the definition of a column. | -| updateColumns | (cols: GridColDef[]) => void | Updates the definition of multiple columns at the same time. | -| updateRows | (updates: GridRowModelUpdate[]) => void | Allows to updates, insert and delete rows in a single call. | -| upsertFilterItem | (item: GridFilterItem) => void | Updates or inserts a GridFilterItem. | +| Name | Type | Description | +| :--------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| addRowGroupingCriteria | (groupingCriteriaField: string, groupingIndex?: number) => void | Add the field to the rowGroupingModel. | +| applySorting | () => void | Applies the current sort model to the rows. | +| commitCellChange | (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the field at the given id with the value stored in the edit row model. | +| commitRowChange | (id: GridRowId, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the row at the given id with the values stored in the edit row model. | +| deleteFilterItem | (item: GridFilterItem) => void | Deletes a GridFilterItem. | +| exportDataAsCsv | (options?: GridCsvExportOptions) => void | Downloads and exports a CSV of the grid's data. | +| exportDataAsPrint | (options?: GridPrintExportOptions) => void | Print the grid's data. | +| forceUpdate | () => void | Forces the grid to rerender. It's often used after a state update. | +| getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/api/data-grid/grid-col-def/) containing all the column definitions. | +| getAllRowIds | () => GridRowId[] | Gets the list of row ids. | +| getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | +| getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | +| getCellParams | (id: GridRowId, field: string) => GridCellParams | Gets the [GridCellParams](/api/data-grid/grid-cell-params/) object that is passed as argument in events. | +| getCellValue | (id: GridRowId, field: string) => GridCellValue | Gets the value of a cell at the given `id` and `field`. | +| getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/api/data-grid/grid-col-def/) for the given `field`. | +| getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | +| getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | +| getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | +| getColumnPosition | (field: string) => number | Returns the left-position of a column relative to the inner border of the grid. | +| getColumnsMeta | () => GridColumnsMeta | Returns the GridColumnsMeta for each column. | +| getDataAsCsv | (options?: GridCsvExportOptions) => string | Returns the grid data as a CSV string.
This method is used internally by `exportDataAsCsv`. | +| getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | +| getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | +| getPinnedColumns | () => GridPinnedColumns | Returns which columns are pinned. | +| getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | +| getRow | (id: GridRowId) => GridRowModel \| null | Gets the row data with a given id. | +| getRowElement | (id: GridRowId) => HTMLDivElement \| null | Gets the underlying DOM element for a row at the given `id`. | +| getRowIdFromRowIndex | (index: number) => GridRowId | Gets the `GridRowId` of a row at a specific index.
The index is based on the sorted but unfiltered row list. | +| getRowIndex | (id: GridRowId) => number | Gets the row index of a row with a given id.
The index is based on the sorted but unfiltered row list. | +| getRowMode | (id: GridRowId) => GridRowMode | Gets the mode of a row. | +| getRowModels | () => Map<GridRowId, GridRowModel> | Gets the full set of rows as Map<GridRowId, GridRowModel>. | +| getRowNode | (id: GridRowId) => GridRowTreeNodeConfig \| null | Gets the row node from the internal tree structure. | +| getRowParams | (id: GridRowId) => GridRowParams | Gets the [GridRowParams](/api/data-grid/grid-row-params/) object that is passed as argument in events. | +| getRowsCount | () => number | Gets the total number of rows in the grid. | +| getScrollPosition | () => GridScrollParams | Returns the current scroll position. | +| getSelectedRows | () => Map<GridRowId, GridRowModel> | Returns an array of the selected rows. | +| getSortedRowIds | () => GridRowId[] | Returns all row ids sorted according to the active sort model. | +| getSortedRows | () => GridRowModel[] | Returns all rows sorted according to the active sort model. | +| getSortModel | () => GridSortModel | Returns the sort model currently applied to the grid. | +| getVisibleColumns | () => GridStateColDef[] | Returns the currently visible columns. | +| getVisibleRowModels | () => Map<GridRowId, GridRowModel> | Returns a sorted `Map` containing only the visible rows. | +| hideColumnMenu | () => void | Hides the column menu that is open. | +| hideFilterPanel | () => void | Hides the filter panel. | +| hidePreferences | () => void | Hides the preferences panel. | +| isCellEditable | (params: GridCellParams) => boolean | Controls if a cell is editable. | +| isColumnPinned | (field: string) => GridPinnedPosition \| false | Returns which side a column is pinned to. | +| isRowSelected | (id: GridRowId) => boolean | Determines if a row is selected or not. | +| pinColumn | (field: string, side: GridPinnedPosition) => void | Pins a column to the left or right side of the grid. | +| publishEvent | GridEventPublisher | Emits an event. | +| removeRowGroupingCriteria | (groupingCriteriaField: string) => void | Remove the field from to rowGroupingModel. | +| resize | () => void | Triggers a resize of the component and recalculation of width and height. | +| scroll | (params: Partial<GridScrollParams>) => void | Triggers the viewport to scroll to the given positions (in pixels). | +| scrollToIndexes | (params: Partial<GridCellIndexCoordinates>) => boolean | Triggers the viewport to scroll to the cell at indexes given by `params`.
Returns `true` if the grid had to scroll to reach the target. | +| selectRow | (id: GridRowId, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of a row. | +| selectRowRange | (range: { startId: GridRowId; endId: GridRowId }, isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of all the selectable rows in a range. | +| selectRows | (ids: GridRowId[], isSelected?: boolean, resetSelection?: boolean) => void | Change the selection state of multiple rows. | +| setCellFocus | (id: GridRowId, field: string) => void | Sets the focus to the cell at the given `id` and `field`. | +| setCellMode | (id: GridRowId, field: string, mode: GridCellMode) => void | Sets the mode of a cell. | +| setColumnHeaderFocus | (field: string, event?: MuiBaseEvent) => void | Sets the focus to the column header at the given `field`. | +| setColumnIndex | (field: string, targetIndexPosition: number) => void | Moves a column from its original position to the position given by `targetIndexPosition`. | +| setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | +| setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | +| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number) => void | Sets the density of the grid. | +| setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | +| setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | +| setFilterLinkOperator | (operator: GridLinkOperator) => void | Changes the GridLinkOperator used to connect the filters. | +| setFilterModel | (model: GridFilterModel) => void | Sets the filter model to the one given by `model`. | +| setPage | (page: number) => void | Sets the displayed page to the value given by `page`. | +| setPageSize | (pageSize: number) => void | Sets the number of displayed rows to the value given by `pageSize`. | +| setPinnedColumns | (pinnedColumns: GridPinnedColumns) => void | Changes the pinned columns. | +| setRowChildrenExpansion | (id: GridRowId, isExpanded: boolean) => void | Expand or collapse a row children. | +| setRowGroupingCriteriaIndex | (groupingCriteriaField: string, groupingIndex: number) => void | Sets the grouping index of a grouping criteria. | +| setRowGroupingModel | (model: GridRowGroupingModel) => void | Sets the columns to use as grouping criteria. | +| setRowMode | (id: GridRowId, mode: GridRowMode) => void | Sets the mode of a row. | +| setRows | (rows: GridRowModel[]) => void | Sets a new set of rows. | +| setSelectionModel | (rowIds: GridRowId[]) => void | Updates the selected rows to be those passed to the `rowIds` argument.
Any row already selected will be unselected. | +| setSortModel | (model: GridSortModel) => void | Updates the sort model and triggers the sorting of rows. | +| setState | (state: GridState \| ((previousState: GridState) => GridState)) => boolean | Sets the whole state of the grid. | +| showColumnMenu | (field: string) => void | Display the column menu under the `field` column. | +| showError | (props: any) => void | Displays the error overlay component. | +| showFilterPanel | (targetColumnField?: string) => void | Shows the filter panel. If `targetColumnField` is given, a filter for this field is also added. | +| showPreferences | (newValue: GridPreferencePanelsValue) => void | Displays the preferences panel. The `newValue` argument controls the content of the panel. | +| sortColumn | (column: GridColDef, direction?: GridSortDirection, allowMultipleSorting?: boolean) => void | Sorts a column. | +| state | GridState | Property that contains the whole state of the grid. | +| subscribeEvent | <E extends GridEventsStr>(event: E, handler: GridEventListener<E>, options?: EventListenerOptions) => () => void | Registers a handler for an event. | +| toggleColumnMenu | (field: string) => void | Toggles the column menu under the `field` column. | +| unpinColumn | (field: string) => void | Unpins a column. | +| updateColumn | (col: GridColDef) => void | Updates the definition of a column. | +| updateColumns | (cols: GridColDef[]) => void | Updates the definition of multiple columns at the same time. | +| updateRows | (updates: GridRowModelUpdate[]) => void | Allows to updates, insert and delete rows in a single call. | +| upsertFilterItem | (item: GridFilterItem) => void | Updates or inserts a GridFilterItem. | diff --git a/docs/pages/api-docs/data-grid/grid-grouping-columns-api.json b/docs/pages/api-docs/data-grid/grid-row-grouping-api.json similarity index 54% rename from docs/pages/api-docs/data-grid/grid-grouping-columns-api.json rename to docs/pages/api-docs/data-grid/grid-row-grouping-api.json index e7a08af2418d9..463d17158f4ff 100644 --- a/docs/pages/api-docs/data-grid/grid-grouping-columns-api.json +++ b/docs/pages/api-docs/data-grid/grid-row-grouping-api.json @@ -1,26 +1,26 @@ { - "name": "GridGroupingColumnsApi", + "name": "GridRowGroupingApi", "description": "", "properties": [ { - "name": "addGroupingCriteria", - "description": "Add the field to the groupingColumnsModel.", + "name": "addRowGroupingCriteria", + "description": "Add the field to the rowGroupingModel.", "type": "(groupingCriteriaField: string, groupingIndex?: number) => void" }, { - "name": "removeGroupingCriteria", - "description": "Remove the field from to groupingColumnsModel.", + "name": "removeRowGroupingCriteria", + "description": "Remove the field from to rowGroupingModel.", "type": "(groupingCriteriaField: string) => void" }, { - "name": "setGroupingColumnsModel", - "description": "Sets the columns to use as grouping criteria.", - "type": "(model: GridGroupingColumnsModel) => void" - }, - { - "name": "setGroupingCriteriaIndex", + "name": "setRowGroupingCriteriaIndex", "description": "Sets the grouping index of a grouping criteria.", "type": "(groupingCriteriaField: string, groupingIndex: number) => void" + }, + { + "name": "setRowGroupingModel", + "description": "Sets the columns to use as grouping criteria.", + "type": "(model: GridRowGroupingModel) => void" } ] } diff --git a/docs/scripts/api/buildInterfacesDocumentation.ts b/docs/scripts/api/buildInterfacesDocumentation.ts index f80d56c1adc89..c7a5b26bd57ff 100644 --- a/docs/scripts/api/buildInterfacesDocumentation.ts +++ b/docs/scripts/api/buildInterfacesDocumentation.ts @@ -43,7 +43,7 @@ const INTERFACES_WITH_DEDICATED_PAGES = [ 'GridPrintExportOptions', 'GridScrollApi', 'GridEditRowApi', - 'GridGroupingColumnsApi', + 'GridRowGroupingApi', 'GridColumnPinningApi', ]; diff --git a/docs/src/pages/components/data-grid/events/events.json b/docs/src/pages/components/data-grid/events/events.json index ca251ff741c19..89c07bb5f2119 100644 --- a/docs/src/pages/components/data-grid/events/events.json +++ b/docs/src/pages/components/data-grid/events/events.json @@ -149,12 +149,6 @@ "params": "GridFilterModel", "event": "MuiEvent<{}>" }, - { - "name": "groupingColumnsModelChange", - "description": "Fired when the grouping columns model changes.", - "params": "GridGroupingColumnsModel", - "event": "MuiEvent<{}>" - }, { "name": "headerSelectionCheckboxChange", "description": "Fired when the value of the selection checkbox of the header is changed", @@ -209,6 +203,12 @@ "params": "GridRowParams", "event": "MuiEvent" }, + { + "name": "rowGroupingModelChange", + "description": "Fired when the row grouping model changes.", + "params": "GridRowGroupingModel", + "event": "MuiEvent<{}>" + }, { "name": "rowMouseEnter", "description": "Fired when the mouse enters the row. Called with a GridRowParams object.", diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js deleted file mode 100644 index 06a1f387f40d4..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; -import ApiDocs from 'docsx/src/modules/components/ApiDocs'; -import api from 'docsx/pages/api-docs/data-grid/grid-grouping-columns-api.json'; - -export default function GroupingColumnsApiNoSnap() { - return ; -} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview deleted file mode 100644 index d26e5a9b16bd0..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx.preview +++ /dev/null @@ -1,9 +0,0 @@ - setGroupingColumnsModel(model)} - experimentalFeatures={{ - groupingColumns: true, - }} -/> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview deleted file mode 100644 index 14a6fdea76cd5..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx.preview +++ /dev/null @@ -1,14 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingApiNoSnap.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingApiNoSnap.js new file mode 100644 index 0000000000000..f48767cda16e1 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingApiNoSnap.js @@ -0,0 +1,7 @@ +import React from 'react'; +import ApiDocs from 'docsx/src/modules/components/ApiDocs'; +import api from 'docsx/pages/api-docs/data-grid/grid-row-grouping-api.json'; + +export default function RowGroupingApiNoSnap() { + return ; +} diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js similarity index 69% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js index d7bf8272e9d9e..b1742b02655ea 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsColDefCanBeGrouped() { +export default function RowGroupingColDefCanBeGrouped() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -63,12 +60,12 @@ export default function GroupingColumnsColDefCanBeGrouped() { columns={columnWithNoDirectorGroup} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx similarity index 68% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx index 0b8c1550e104a..721f2759b6512 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsColDefCanBeGrouped() { +export default function RowGroupingColDefCanBeGrouped() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -74,12 +71,12 @@ export default function GroupingColumnsColDefCanBeGrouped() { columns={columnWithNoDirectorGroup} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx.preview similarity index 81% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx.preview index 16342c14b0a8b..a26c7811624ce 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx.preview @@ -4,11 +4,11 @@ columns={columnWithNoDirectorGroup} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.js similarity index 63% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.js index 2995e9fb95e11..ad652179f6119 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.js @@ -4,11 +4,11 @@ import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -export default function GroupingColumnsControlled() { +export default function RowGroupingControlled() { const data = useMovieData(); const apiRef = useGridApiRef(); - const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + const [rowGroupingModel, setRowGroupingModel] = React.useState( INITIAL_GROUPING_COLUMN_MODEL, ); @@ -17,10 +17,10 @@ export default function GroupingColumnsControlled() { setGroupingColumnsModel(model)} + rowGroupingModel={rowGroupingModel} + onRowGroupingModelChange={(model) => setRowGroupingModel(model)} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx similarity index 55% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx index 0ab148b3f1075..85bebb441a339 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsControlled.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx @@ -1,29 +1,29 @@ import * as React from 'react'; import { DataGridPro, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -export default function GroupingColumnsControlled() { +export default function RowGroupingControlled() { const data = useMovieData(); const apiRef = useGridApiRef(); - const [groupingColumnsModel, setGroupingColumnsModel] = - React.useState(INITIAL_GROUPING_COLUMN_MODEL); + const [rowGroupingModel, setRowGroupingModel] = + React.useState(INITIAL_GROUPING_COLUMN_MODEL); return (
setGroupingColumnsModel(model)} + rowGroupingModel={rowGroupingModel} + onRowGroupingModelChange={(model) => setRowGroupingModel(model)} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx.preview new file mode 100644 index 0000000000000..4c9424ee2393f --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingControlled.tsx.preview @@ -0,0 +1,9 @@ + setRowGroupingModel(model)} + experimentalFeatures={{ + rowGrouping: true, + }} +/> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.js similarity index 62% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.js index b1f1f6ecc6a77..cb01ebdcd90c9 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.js @@ -11,21 +11,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -40,10 +37,10 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsCustomGroupingColDefCallback() { +export default function RowGroupingCustomGroupingColDefCallback() { const data = useMovieData(); const apiRef = useGridApiRef(); - const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + const [rowGroupingModel, setRowGroupingModel] = React.useState( INITIAL_GROUPING_COLUMN_MODEL, ); @@ -53,7 +50,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { INITIAL_GROUPING_COLUMN_MODEL, ); - const groupingColumnsModelStr = groupingColumnsModel.join('-'); + const rowGroupingModelStr = rowGroupingModel.join('-'); return (
@@ -65,17 +62,15 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { > setGroupingColumnsModel(['company'])} + onClick={() => setRowGroupingModel(['company'])} variant="outlined" - color={groupingColumnsModelStr === 'company' ? 'primary' : undefined} + color={rowGroupingModelStr === 'company' ? 'primary' : undefined} /> setGroupingColumnsModel(['company', 'director'])} + onClick={() => setRowGroupingModel(['company', 'director'])} variant="outlined" - color={ - groupingColumnsModelStr === 'company-director' ? 'primary' : undefined - } + color={rowGroupingModelStr === 'company-director' ? 'primary' : undefined} /> @@ -84,7 +79,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { apiRef={apiRef} columns={columns} disableSelectionOnClick - groupingColumnsModel={groupingColumnsModel} + rowGroupingModel={rowGroupingModel} groupingColDef={(params) => params.fields.includes('director') ? { @@ -93,7 +88,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { : {} } experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.tsx similarity index 61% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.tsx index 237a972b8c585..5df29e6313175 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -17,26 +17,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -51,10 +48,10 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsCustomGroupingColDefCallback() { +export default function RowGroupingCustomGroupingColDefCallback() { const data = useMovieData(); const apiRef = useGridApiRef(); - const [groupingColumnsModel, setGroupingColumnsModel] = React.useState( + const [rowGroupingModel, setRowGroupingModel] = React.useState( INITIAL_GROUPING_COLUMN_MODEL, ); @@ -64,7 +61,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { INITIAL_GROUPING_COLUMN_MODEL, ); - const groupingColumnsModelStr = groupingColumnsModel.join('-'); + const rowGroupingModelStr = rowGroupingModel.join('-'); return (
@@ -76,17 +73,15 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { > setGroupingColumnsModel(['company'])} + onClick={() => setRowGroupingModel(['company'])} variant="outlined" - color={groupingColumnsModelStr === 'company' ? 'primary' : undefined} + color={rowGroupingModelStr === 'company' ? 'primary' : undefined} /> setGroupingColumnsModel(['company', 'director'])} + onClick={() => setRowGroupingModel(['company', 'director'])} variant="outlined" - color={ - groupingColumnsModelStr === 'company-director' ? 'primary' : undefined - } + color={rowGroupingModelStr === 'company-director' ? 'primary' : undefined} /> @@ -95,7 +90,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { apiRef={apiRef} columns={columns} disableSelectionOnClick - groupingColumnsModel={groupingColumnsModel} + rowGroupingModel={rowGroupingModel} groupingColDef={(params) => params.fields.includes('director') ? { @@ -104,7 +99,7 @@ export default function GroupingColumnsCustomGroupingColDefCallback() { : {} } experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.js similarity index 67% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.js index 3dce1cbd4f729..f246b7122a8c1 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsCustomGroupingColDefObject() { +export default function RowGroupingCustomGroupingColDefObject() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -55,7 +52,7 @@ export default function GroupingColumnsCustomGroupingColDefObject() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} @@ -63,7 +60,7 @@ export default function GroupingColumnsCustomGroupingColDefObject() { headerName: 'Group', }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.tsx similarity index 66% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.tsx index b19bd4470b37a..3d1bff2c2c297 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsCustomGroupingColDefObject() { +export default function RowGroupingCustomGroupingColDefObject() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -66,7 +63,7 @@ export default function GroupingColumnsCustomGroupingColDefObject() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} @@ -74,7 +71,7 @@ export default function GroupingColumnsCustomGroupingColDefObject() { headerName: 'Group', }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.js similarity index 67% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.js index f3146d295b997..26e21f4e0002e 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsDefaultExpansionDepth() { +export default function RowGroupingDefaultExpansionDepth() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -56,12 +53,12 @@ export default function GroupingColumnsDefaultExpansionDepth() { defaultGroupingExpansionDepth={-1} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx similarity index 65% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx index 2421a7ced51f5..c66763ef4f779 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsDefaultExpansionDepth() { +export default function RowGroupingDefaultExpansionDepth() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -67,12 +64,12 @@ export default function GroupingColumnsDefaultExpansionDepth() { defaultGroupingExpansionDepth={-1} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} />
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx.preview similarity index 82% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx.preview index 134059cd85437..c4d72475b08ce 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.tsx.preview @@ -5,11 +5,11 @@ defaultGroupingExpansionDepth={-1} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.js similarity index 76% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.js index 19f0dca8f3da3..6e63ab094d572 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { DataGridPro } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; -export default function GroupingColumnsDisabled() { +export default function RowGroupingDisabled() { const data = useMovieData(); return ( @@ -10,9 +10,9 @@ export default function GroupingColumnsDisabled() {
diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx similarity index 76% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx index 19f0dca8f3da3..6e63ab094d572 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { DataGridPro } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; -export default function GroupingColumnsDisabled() { +export default function RowGroupingDisabled() { const data = useMovieData(); return ( @@ -10,9 +10,9 @@ export default function GroupingColumnsDisabled() { diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx.preview similarity index 61% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx.preview index a33ed2d386560..fdada4b2514bb 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsDisabled.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingDisabled.tsx.preview @@ -1,8 +1,8 @@ \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.js similarity index 71% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.js index 7e058768baabd..6c56567d23d61 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsFullExample() { +export default function RowGroupingFullExample() { const { data, loading } = useDemoData({ dataSet: 'Commodity', rowLength: 100, @@ -61,7 +58,7 @@ export default function GroupingColumnsFullExample() { loading={loading} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, sorting: { @@ -72,7 +69,7 @@ export default function GroupingColumnsFullExample() { leafField: 'traderEmail', }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.tsx similarity index 69% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.tsx index dd3169421b240..48a9c5d775909 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsFullExample.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingFullExample.tsx @@ -5,7 +5,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['commodity']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsFullExample() { +export default function RowGroupingFullExample() { const { data, loading } = useDemoData({ dataSet: 'Commodity', rowLength: 100, @@ -71,7 +68,7 @@ export default function GroupingColumnsFullExample() { loading={loading} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, sorting: { @@ -82,7 +79,7 @@ export default function GroupingColumnsFullExample() { leafField: 'traderEmail', }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js similarity index 67% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js index 09ca5a53d88bb..55750bb9e9fd9 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsHideDescendantCount() { +export default function RowGroupingHideDescendantCount() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -55,7 +52,7 @@ export default function GroupingColumnsHideDescendantCount() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} @@ -63,7 +60,7 @@ export default function GroupingColumnsHideDescendantCount() { hideDescendantCount: true, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.tsx similarity index 66% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.tsx index 390c14bf81743..370027695b95a 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsHideDescendantCount() { +export default function RowGroupingHideDescendantCount() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -66,7 +63,7 @@ export default function GroupingColumnsHideDescendantCount() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} @@ -74,7 +71,7 @@ export default function GroupingColumnsHideDescendantCount() { hideDescendantCount: true, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.js similarity index 83% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.js index f820cc24e3833..70cbb5a571b40 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.js @@ -4,7 +4,7 @@ import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -export default function GroupingColumnsInitialState() { +export default function RowGroupingInitialState() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -15,12 +15,12 @@ export default function GroupingColumnsInitialState() { apiRef={apiRef} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx similarity index 83% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx index f820cc24e3833..70cbb5a571b40 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx @@ -4,7 +4,7 @@ import { useMovieData } from '@mui/x-data-grid-generator'; const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; -export default function GroupingColumnsInitialState() { +export default function RowGroupingInitialState() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -15,12 +15,12 @@ export default function GroupingColumnsInitialState() { apiRef={apiRef} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx.preview similarity index 77% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx.preview index 4db34cce3e029..97fdf5f5d8301 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsInitialState.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingInitialState.tsx.preview @@ -3,11 +3,11 @@ apiRef={apiRef} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js similarity index 71% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js index cc986dffe008a..7e14b635d1a40 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsKeyGetter() { +export default function RowGroupingKeyGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -68,12 +65,12 @@ export default function GroupingColumnsKeyGetter() { apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx similarity index 71% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx index 543232954bbde..483d91569cbda 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, GridKeyGetterParams, GridRenderCellParams, useGridApiRef, @@ -16,26 +16,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['composer']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -50,7 +47,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsKeyGetter() { +export default function RowGroupingKeyGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -83,12 +80,12 @@ export default function GroupingColumnsKeyGetter() { apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx.preview similarity index 77% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx.preview index 9551cf41a1467..d99ba502224bd 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx.preview @@ -3,11 +3,11 @@ apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js similarity index 74% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js index 8b3ddb57234ea..5f76a9acc4924 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsKeyGetterValueGetter() { +export default function RowGroupingKeyGetterValueGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -79,12 +76,12 @@ export default function GroupingColumnsKeyGetterValueGetter() { apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx similarity index 74% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx index fee7809ae7eb0..0be48ac2fe2c6 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, GridKeyGetterParams, GridRenderCellParams, useGridApiRef, @@ -18,26 +18,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['decade']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -52,7 +49,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsKeyGetterValueGetter() { +export default function RowGroupingKeyGetterValueGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -96,12 +93,12 @@ export default function GroupingColumnsKeyGetterValueGetter() { apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview similarity index 77% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview index 9551cf41a1467..d99ba502224bd 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview @@ -3,11 +3,11 @@ apiRef={apiRef} columns={columns} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.js similarity index 67% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.js index 2b2bc132c7a9e..305be779e1931 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsLeafWithValue() { +export default function RowGroupingLeafWithValue() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -56,12 +53,12 @@ export default function GroupingColumnsLeafWithValue() { columns={columns} groupingColDef={{ leafField: 'title' }} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx similarity index 65% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx index 8a15f65ed3740..98d9a2fa99deb 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsLeafWithValue() { +export default function RowGroupingLeafWithValue() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -67,12 +64,12 @@ export default function GroupingColumnsLeafWithValue() { columns={columns} groupingColDef={{ leafField: 'title' }} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx.preview similarity index 80% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx.preview index 019f7e08baea6..409eb7b562312 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.tsx.preview @@ -4,11 +4,11 @@ columns={columns} groupingColDef={{ leafField: 'title' }} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js similarity index 64% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js index 8c20f0833f58c..20fecd466dbc3 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsSingleGroupingCol() { +export default function RowGroupingMultipleGroupingCol() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -53,14 +50,14 @@ export default function GroupingColumnsSingleGroupingCol() { {...data} apiRef={apiRef} columns={columns} - groupingColumnMode="single" + rowGroupingColumnMode="multiple" initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx similarity index 63% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx index 1a4405b8d19fa..20513d7b80d6d 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsSingleGroupingCol() { +export default function RowGroupingMultipleGroupingCol() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -64,14 +61,14 @@ export default function GroupingColumnsSingleGroupingCol() { {...data} apiRef={apiRef} columns={columns} - groupingColumnMode="single" + rowGroupingColumnMode="multiple" initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx.preview similarity index 68% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx.preview index 3bade81ba2f19..867f47cf95155 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.tsx.preview @@ -2,13 +2,13 @@ {...data} apiRef={apiRef} columns={columns} - groupingColumnMode="single" + rowGroupingColumnMode="multiple" initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.js similarity index 66% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.js index 4751accb689c5..524f67f7afd01 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsRowsWithMissingGroups() { +export default function RowGroupingRowsWithMissingGroups() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -55,12 +52,12 @@ export default function GroupingColumnsRowsWithMissingGroups() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx similarity index 65% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx index ec7a94fde0a44..13e4bb0575b88 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['cinematicUniverse']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsRowsWithMissingGroups() { +export default function RowGroupingRowsWithMissingGroups() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -66,12 +63,12 @@ export default function GroupingColumnsRowsWithMissingGroups() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx.preview similarity index 79% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx.preview index d8316eba2e773..4239560aa49d4 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.tsx.preview @@ -4,11 +4,11 @@ columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.js similarity index 74% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.js index fc09f030b4bb6..2ff6b08f1fda9 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.js @@ -15,21 +15,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -44,7 +41,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsSetChildrenExpansion() { +export default function RowGroupingSetChildrenExpansion() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -76,12 +73,12 @@ export default function GroupingColumnsSetChildrenExpansion() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.tsx similarity index 73% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.tsx index 3dba60920bb81..b5a24e16c4084 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, gridVisibleSortedRowIdsSelector, useGridApiRef, } from '@mui/x-data-grid-pro'; @@ -17,26 +17,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -51,7 +48,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsSetChildrenExpansion() { +export default function RowGroupingSetChildrenExpansion() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -83,12 +80,12 @@ export default function GroupingColumnsSetChildrenExpansion() { columns={columns} disableSelectionOnClick initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js similarity index 64% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js index 7d3c32b1e51a0..d1a287d20afdd 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsMultipleGroupingCol() { +export default function RowGroupingSingleGroupingCol() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -53,14 +50,14 @@ export default function GroupingColumnsMultipleGroupingCol() { {...data} apiRef={apiRef} columns={columns} - groupingColumnMode="multiple" + rowGroupingColumnMode="single" initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx similarity index 63% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx index acfd63edcf800..2f2548da65b43 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsMultipleGroupingCol() { +export default function RowGroupingSingleGroupingCol() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -64,14 +61,14 @@ export default function GroupingColumnsMultipleGroupingCol() { {...data} apiRef={apiRef} columns={columns} - groupingColumnMode="multiple" + rowGroupingColumnMode="single" initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx.preview new file mode 100644 index 0000000000000..3ebe5d5b5a813 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.js similarity index 69% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.js index d203e7113bcda..4f91a497ef1d8 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.js @@ -8,21 +8,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -37,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsSortingMultipleGroupingColDef() { +export default function RowGroupingSortingMultipleGroupingColDef() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -56,11 +53,11 @@ export default function GroupingColumnsSortingMultipleGroupingColDef() { disableSelectionOnClick defaultGroupingExpansionDepth={-1} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} - groupingColumnMode="multiple" + rowGroupingColumnMode="multiple" groupingColDef={(params) => params.fields.includes('director') ? { @@ -70,7 +67,7 @@ export default function GroupingColumnsSortingMultipleGroupingColDef() { : {} } experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.tsx similarity index 67% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.tsx index dcf3070051c90..eaed26ecd704a 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -14,26 +14,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -48,7 +45,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsSortingMultipleGroupingColDef() { +export default function RowGroupingSortingMultipleGroupingColDef() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -67,11 +64,11 @@ export default function GroupingColumnsSortingMultipleGroupingColDef() { disableSelectionOnClick defaultGroupingExpansionDepth={-1} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} - groupingColumnMode="multiple" + rowGroupingColumnMode="multiple" groupingColDef={(params) => params.fields.includes('director') ? { @@ -81,7 +78,7 @@ export default function GroupingColumnsSortingMultipleGroupingColDef() { : {} } experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.js similarity index 79% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.js index 77ad049c91460..8c90b0cf91077 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.js @@ -13,21 +13,18 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); - prevModel.current = initialModel; - }, - ); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -42,7 +39,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function GroupingColumnsSortingSingleGroupingColDef() { +export default function RowGroupingSortingSingleGroupingColDef() { const data = useMovieData(); const [mainGroupingCriteria, setMainGroupingCriteria] = React.useState('undefined'); @@ -84,11 +81,11 @@ export default function GroupingColumnsSortingSingleGroupingColDef() { disableSelectionOnClick defaultGroupingExpansionDepth={-1} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} - groupingColumnMode="single" + rowGroupingColumnMode="single" groupingColDef={{ mainGroupingCriteria: mainGroupingCriteria === 'undefined' @@ -96,7 +93,7 @@ export default function GroupingColumnsSortingSingleGroupingColDef() { : mainGroupingCriteria, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.tsx similarity index 78% rename from docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.tsx index be42d5e616e6c..726b06fe7aed7 100644 --- a/docs/src/pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.tsx @@ -4,7 +4,7 @@ import { GridApiRef, GridColumns, GridEvents, - GridGroupingColumnsModel, + GridRowGroupingModel, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; @@ -19,26 +19,23 @@ const INITIAL_GROUPING_COLUMN_MODEL = ['company', 'director']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, columns: GridColumns, - initialModel: GridGroupingColumnsModel, + initialModel: GridRowGroupingModel, leafField?: string, ) => { const prevModel = React.useRef(initialModel); React.useEffect(() => { - apiRef.current.subscribeEvent( - GridEvents.groupingColumnsModelChange, - (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }, - ); + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); }, [apiRef, initialModel]); return React.useMemo( @@ -53,7 +50,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function GroupingColumnsSortingSingleGroupingColDef() { +export default function RowGroupingSortingSingleGroupingColDef() { const data = useMovieData(); const [mainGroupingCriteria, setMainGroupingCriteria] = React.useState('undefined'); @@ -95,11 +92,11 @@ export default function GroupingColumnsSortingSingleGroupingColDef() { disableSelectionOnClick defaultGroupingExpansionDepth={-1} initialState={{ - groupingColumns: { + rowGrouping: { model: INITIAL_GROUPING_COLUMN_MODEL, }, }} - groupingColumnMode="single" + rowGroupingColumnMode="single" groupingColDef={{ mainGroupingCriteria: mainGroupingCriteria === 'undefined' @@ -107,7 +104,7 @@ export default function GroupingColumnsSortingSingleGroupingColDef() { : mainGroupingCriteria, }} experimentalFeatures={{ - groupingColumns: true, + rowGrouping: true, }} /> diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index b8bb377d3ea77..7cc44e08039ed 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -6,16 +6,16 @@ title: Data Grid - Group & Pivot

Use grouping, pivoting, and more to analyze the data in depth.

-## Grouping Columns [](https://mui.com/store/items/material-ui-pro/) +## Row grouping [](https://mui.com/store/items/material-ui-pro/) Use grouping columns to group the rows according to one or several columns value

> ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. > -> To avoid future regression for users of the Pro plan, the feature needs to be explicitly activated using the `groupingColumns` experimental feature flag. +> To avoid future regression for users of the Pro plan, the feature needs to be explicitly activated using the `rowGrouping` experimental feature flag. > > ```tsx -> +> > ``` > > The feature is stable in its current form, and we encourage users willing to migrate to the Premium plan once available to start using it. @@ -28,62 +28,62 @@ To initialize the grouping columns without controlling them, provide the model t ```ts initialState={{ - groupingColumns: { + rowGrouping: { model: ['director', 'category'] } }} ``` -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsInitialState.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingInitialState.js", "bg": "inline", "defaultCodeOpen": false}} #### Controlling the grouping columns -To fully control the grouping columns, provide the model to the `groupingColumnsModel` prop. -Use it together with `onGroupingColumnsModelChange` to know when a grouping criteria is added or removed. +To fully control the grouping columns, provide the model to the `rowGroupingModel` prop. +Use it together with `onRowGroupingModelChange` to know when a grouping criteria is added or removed. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsControlled.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingControlled.js", "bg": "inline", "defaultCodeOpen": false}} ### Disable the grouping #### Fully disable the grouping -To fully disable the grouping feature, set the `disableGroupingColumns` prop to `true`. +To fully disable the grouping feature, set the `disableRowGrouping` prop to `true`. It will disable all the features related to the grouping columns, even if a model is provided. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsDisabled.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingDisabled.js", "bg": "inline", "defaultCodeOpen": false}} #### Disable the grouping for some columns To block the grouping of certain columns, set the `canBeGrouped` property of `GridColDef` to `false`. In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} #### Single grouping column By default, the grid will create only one grouping column even if you have several grouping criteria. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} #### Multiple grouping column -To have a grouping column for each grouping criteria, set the `groupingColumnMode` prop to `multiple`. +To have a grouping column for each grouping criteria, set the `rowGroupingColumnMode` prop to `multiple`. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} -### Grouping column customization +### Custom grouping column Use the `groupingColDef` prop to customize the rendering of the grouping column. You can override any property of the `GridColDef` interface except the `field`, the `type` and the properties related to the edition. If you want to apply your overrides to every grouping column, use the object format of `groupingColDef`. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefObject.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.js", "bg": "inline", "defaultCodeOpen": false}} If you want to only override properties of certain grouping columns or to apply different overrides based on the current grouping criteria, use the callback format of `groupingColDef`. It will be called for each grouping column with the fields of the columns used to build it. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsCustomGroupingColDefCallback.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.js", "bg": "inline", "defaultCodeOpen": false}} #### Show values for the leaves @@ -91,13 +91,13 @@ By default, the leaves nodes don't render anything for their grouping cell. If you want to display some value, you can provide a `leafField` property to the `groupingColDef`. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsLeafWithValue.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingLeafWithValue.js", "bg": "inline", "defaultCodeOpen": false}} #### Hide the descendant count You can use the `hideDescendantCount` property of the `groupingColDef` to hide the amount of descendant of a grouping row. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsHideDescendantCount.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js", "bg": "inline", "defaultCodeOpen": false}} ### Complex grouping value @@ -116,34 +116,34 @@ const columns: GridColumns = [ ]; ``` -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsKeyGetter.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js", "bg": "inline", "defaultCodeOpen": false}} If your column also have a `valueGetter` property, the value passed to the `keyGetter` property will be the one returned by `valueGetter`. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsKeyGetterValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} ### Rows with missing groups If the grouping key of a grouping criteria is `null` or `undefined` for a row, the grid will consider that this row do not have a value for this group. and will inline it for those groups. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsRowsWithMissingGroups.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.js", "bg": "inline", "defaultCodeOpen": false}} ### Group expansion Use the `defaultGroupingExpansionDepth` prop to expand all the groups up to a given depth when loading the data. If you want to expand the whole tree, set `defaultGroupingExpansionDepth = -1` -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsDefaultExpansionDepth.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.js", "bg": "inline", "defaultCodeOpen": false}} Use the `setRowChildrenExpansion` method on `apiRef` to programmatically set the expansion of a row. -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSetChildrenExpansion.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSetChildrenExpansion.js", "bg": "inline", "defaultCodeOpen": false}} ### Sorting / Filtering #### Single grouping column -When using `groupingColumnMode = "single"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the top level grouping criteria. +When using `rowGroupingColumnMode = "single"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the top level grouping criteria. If you are rendering leaves with the `leafField` property of `groupColDef`, the sorting and filtering will be applied on the leaves based on the `sortComparator` and `filterOperators` of their original column. @@ -151,11 +151,11 @@ In both cases, you can force the sorting and filtering to be applied on another > ⚠️ This feature is not yet compatible with `sortingMode = "server` and `filteringMode = "server"` -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSortingSingleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSortingSingleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} #### Multiple grouping column -When using `groupingColumnMode = "multiple"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the grouping criteria of each grouping column. +When using `rowGroupingColumnMode = "multiple"`, the default behavior is to apply the `sortComparator` and `filterOperators` of the grouping criteria of each grouping column. If you are rendering leaves on one of those columns with the `leafField` property of `groupColDef`, the sorting and filtering will be applied on the leaves for this grouping column based on the `sortComparator` and `filterOperators` of the leave's original column. @@ -166,17 +166,17 @@ In the example below: - the sorting and filtering of the `company` grouping column is applied on the `company` field - the sorting and filtering of the `director` grouping column is applied on the `director` field even though it has leaves -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsSortingMultipleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSortingMultipleGroupingColDef.js", "bg": "inline", "defaultCodeOpen": false}} > ⚠️ If you are dynamically switching the `leafField` or `mainGroupingCriteria`, the sorting and filtering models will not automatically be cleaned-up and the sorting / filtering will not be re-applied. ### Full example -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsFullExample.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingFullExample.js", "bg": "inline", "defaultCodeOpen": false}} ### apiRef [](https://mui.com/store/items/material-ui-pro/) -{{"demo": "pages/components/data-grid/group-pivot/GroupingColumnsApiNoSnap.js", "bg": "inline", "hideToolbar": true}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingApiNoSnap.js", "bg": "inline", "hideToolbar": true}} ## Tree Data [](https://mui.com/store/items/material-ui-pro/) @@ -227,7 +227,7 @@ const rows: GridRowsProp = [ {{"demo": "pages/components/data-grid/group-pivot/TreeDataSimple.js", "bg": "inline", "defaultCodeOpen": false}} -### Grouping column customization +### Custom grouping column Same behavior as for the [Grouping Columns](##grouping-column-customization) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index 6c821c8de6705..2adaa71d82262 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -27,10 +27,10 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", - "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", + "disableRowGrouping": "If true, the grouping columns are disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -44,8 +44,6 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -80,7 +78,6 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", - "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -90,6 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", + "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -101,6 +99,8 @@ "pinnedColumns": "The column fields to display pinned to left or right.", "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", + "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "rowGroupingModel": "Set the grouping columns of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index 6c821c8de6705..2adaa71d82262 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -27,10 +27,10 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", - "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", + "disableRowGrouping": "If true, the grouping columns are disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -44,8 +44,6 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -80,7 +78,6 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", - "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -90,6 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", + "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -101,6 +99,8 @@ "pinnedColumns": "The column fields to display pinned to left or right.", "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", + "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "rowGroupingModel": "Set the grouping columns of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index 6c821c8de6705..2adaa71d82262 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -27,10 +27,10 @@ "disableColumnSelector": "If true, hiding/showing columns is disabled.", "disableDensitySelector": "If true, the density selector is disabled.", "disableExtendRowFullWidth": "If true, rows will not be extended to fill the full width of the grid container.", - "disableGroupingColumns": "If true, the grouping columns are disabled.", "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", + "disableRowGrouping": "If true, the grouping columns are disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -44,8 +44,6 @@ "getRowId": "Return the id of a given GridRowModel.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: GridRowModel) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "groupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "groupingColumnsModel": "Set the grouping columns of the grid.", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -80,7 +78,6 @@ "onEditRowsModelChange": "Callback fired when the editRowsModel changes.

Signature:
function(editRowsModel: GridEditRowsModel, details: GridCallbackDetails) => void
editRowsModel: With all properties from GridEditRowsModel.
details: Additional details for this callback.", "onError": "Callback fired when an exception is thrown in the grid.

Signature:
function(args: any, event: MuiEvent<{}>, details: GridCallbackDetails) => void
args: The arguments passed to the showError call.
event: The event object.
details: Additional details for this callback.", "onFilterModelChange": "Callback fired when the Filter model changes before the filters are applied.

Signature:
function(model: GridFilterModel, details: GridCallbackDetails) => void
model: With all properties from GridFilterModel.
details: Additional details for this callback.", - "onGroupingColumnsModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridGroupingColumnsModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onPageChange": "Callback fired when the current page has changed.

Signature:
function(page: number, details: GridCallbackDetails) => void
page: Index of the page displayed on the Grid.
details: Additional details for this callback.", "onPageSizeChange": "Callback fired when the page size has changed.

Signature:
function(pageSize: number, details: GridCallbackDetails) => void
pageSize: Size of the page displayed on the Grid.
details: Additional details for this callback.", "onPinnedColumnsChange": "Callback fired when the pinned columns have changed.

Signature:
function(pinnedColumns: GridPinnedColumns, details: GridCallbackDetails) => void
pinnedColumns: The changed pinned columns.
details: Additional details for this callback.", @@ -90,6 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", + "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -101,6 +99,8 @@ "pinnedColumns": "The column fields to display pinned to left or right.", "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", + "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", + "rowGroupingModel": "Set the grouping columns of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/packages/grid/_modules_/grid/GridComponentProps.ts b/packages/grid/_modules_/grid/GridComponentProps.ts index bc9fb24198c08..af066dde568e8 100644 --- a/packages/grid/_modules_/grid/GridComponentProps.ts +++ b/packages/grid/_modules_/grid/GridComponentProps.ts @@ -27,7 +27,7 @@ import { GridClasses } from './gridClasses'; import { GridCallbackDetails } from './models/api/gridCallbackDetails'; import { GridPinnedColumns } from './models/api/gridColumnPinningApi'; import { GridEventListener, GridEvents } from './models/events'; -import type { GridGroupingColumnsModel } from './hooks/features/groupingColumns'; +import type { GridRowGroupingModel } from './hooks/features/rowGrouping'; /** * The grid component react props before applying the default values. @@ -366,16 +366,13 @@ interface GridComponentOtherProps extends CommonProps { /** * Set the grouping columns of the grid. */ - groupingColumnsModel?: GridGroupingColumnsModel; + rowGroupingModel?: GridRowGroupingModel; /** * Callback fired when the grouping columns model changes. - * @param {GridGroupingColumnsModel} model Columns used as grouping criteria. + * @param {GridRowGroupingModel} model Columns used as grouping criteria. * @param {GridCallbackDetails} details Additional details for this callback. */ - onGroupingColumnsModelChange?: ( - model: GridGroupingColumnsModel, - details: GridCallbackDetails, - ) => void; + onRowGroupingModelChange?: (model: GridRowGroupingModel, details: GridCallbackDetails) => void; /** * The column fields to display pinned to left or right. */ diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx index efedcebdad075..c66119bdcf591 100644 --- a/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingColumnLeafCell.tsx @@ -8,7 +8,7 @@ const GridGroupingColumnLeafCell = (props: GridRenderCellParams) => { const rootProps = useGridRootProps(); - const marginLeft = rootProps.groupingColumnMode === 'multiple' ? 1 : rowNode.depth * 2; + const marginLeft = rootProps.rowGroupingColumnMode === 'multiple' ? 1 : rowNode.depth * 2; return {props.formattedValue ?? props.value}; }; diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx index 00ce3e18bb7a4..da6da9da8262a 100644 --- a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx @@ -62,7 +62,7 @@ const GridGroupingCriteriaCell = (props: GridGroupingCriteriaCellProps) => { event.stopPropagation(); }; - const marginLeft = rootProps.groupingColumnMode === 'multiple' ? 0 : rowNode.depth * 2; + const marginLeft = rootProps.rowGroupingColumnMode === 'multiple' ? 0 : rowNode.depth * 2; return ( diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx similarity index 79% rename from packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx rename to packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx index 3f47ffd9a242d..3235c7a0d14b6 100644 --- a/packages/grid/_modules_/grid/components/menu/columnMenu/GridGroupingColumnsMenuItems.tsx +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx @@ -5,12 +5,12 @@ import Divider from '@mui/material/Divider'; import { useGridApiContext } from '../../../hooks/utils/useGridApiContext'; import { GridColDef } from '../../../models/colDef/gridColDef'; import { useGridSelector } from '../../../hooks/utils/useGridSelector'; -import { gridGroupingColumnsSanitizedModelSelector } from '../../../hooks/features/groupingColumns/gridGroupingColumnsSelector'; +import { gridRowGroupingSanitizedModelSelector } from '../../../hooks/features/rowGrouping/gridRowGroupingSelector'; import { getGroupingCriteriaFieldFromGroupingColDefField, GROUPING_COLUMN_SINGLE, isGroupingColumn, -} from '../../../hooks/features/groupingColumns/gridGroupingColumnsUtils'; +} from '../../../hooks/features/rowGrouping/gridRowGroupingUtils'; import { gridColumnLookupSelector } from '../../../hooks/features/columns/gridColumnsSelector'; interface GridGroupingColumnsMenuItemsProps { @@ -18,22 +18,22 @@ interface GridGroupingColumnsMenuItemsProps { onClick?: (event: React.MouseEvent) => void; } -const GridGroupingColumnsMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { +const GridRowGroupingMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { const { column, onClick } = props; const apiRef = useGridApiContext(); - const groupingColumnsModel = useGridSelector(apiRef, gridGroupingColumnsSanitizedModelSelector); + const rowGroupingModel = useGridSelector(apiRef, gridRowGroupingSanitizedModelSelector); const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector); const isGrouped = React.useMemo( - () => column?.field && groupingColumnsModel.includes(column.field), - [column, groupingColumnsModel], + () => column?.field && rowGroupingModel.includes(column.field), + [column, rowGroupingModel], ); const renderGroupingMenuItem = (field: string) => { const name = columnsLookup[field].headerName ?? field; const groupColumn = (event: React.MouseEvent) => { - apiRef.current.addGroupingCriteria(field); + apiRef.current.addRowGroupingCriteria(field); if (onClick) { onClick(event); } @@ -46,7 +46,7 @@ const GridGroupingColumnsMenuItems = (props: GridGroupingColumnsMenuItemsProps) const renderUnGroupingMenuItem = (field: string) => { const ungroupColumn = (event: React.MouseEvent) => { - apiRef.current.removeGroupingCriteria(field); + apiRef.current.removeRowGroupingCriteria(field); if (onClick) { onClick(event); } @@ -70,7 +70,7 @@ const GridGroupingColumnsMenuItems = (props: GridGroupingColumnsMenuItemsProps) return ( - {groupingColumnsModel.map(renderUnGroupingMenuItem)} + {rowGroupingModel.map(renderUnGroupingMenuItem)} ); } @@ -104,7 +104,7 @@ const GridGroupingColumnsMenuItems = (props: GridGroupingColumnsMenuItemsProps) ); }; -GridGroupingColumnsMenuItems.propTypes = { +GridRowGroupingMenuItems.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | @@ -113,4 +113,4 @@ GridGroupingColumnsMenuItems.propTypes = { onClick: PropTypes.func, } as any; -export { GridGroupingColumnsMenuItems }; +export { GridRowGroupingMenuItems }; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts deleted file mode 100644 index 19e550dccd0a6..0000000000000 --- a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsInterfaces.ts +++ /dev/null @@ -1,37 +0,0 @@ -export type GridGroupingColumnsModel = string[]; - -export interface GridGroupingColumnsState { - model: GridGroupingColumnsModel; -} - -export interface GridGroupingColumnsInitialState { - model?: GridGroupingColumnsModel; -} - -export interface GridGroupingColumnsApi { - /** - * Sets the columns to use as grouping criteria. - * @param {GridGroupingColumnsModel} model The columns to use as grouping criteria. - */ - setGroupingColumnsModel: (model: GridGroupingColumnsModel) => void; - - /** - * Add the field to the groupingColumnsModel. - * @param {string} groupingCriteriaField The field from which we want to group the rows. - * @param {number | undefined} groupingIndex The grouping index at which we want to insert the new grouping criteria. By default, it will be inserted at the end of the model. - */ - addGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => void; - - /** - * Remove the field from to groupingColumnsModel. - * @param {string} groupingCriteriaField The field from which we want to stop grouping the rows. - */ - removeGroupingCriteria: (groupingCriteriaField: string) => void; - - /** - * Sets the grouping index of a grouping criteria. - * @param {string} groupingCriteriaField The field of the grouping criteria from which we want to change the grouping index. - * @param {number} groupingIndex The new grouping index of this grouping criteria. - */ - setGroupingCriteriaIndex: (groupingCriteriaField: string, groupingIndex: number) => void; -} diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts deleted file mode 100644 index 7793d7a35b6fb..0000000000000 --- a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsSelector.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createSelector } from 'reselect'; -import { GridState } from '../../../models'; -import { gridColumnLookupSelector } from '../columns'; - -export const gridGroupingColumnsStateSelector = (state: GridState) => state.groupingColumns; - -export const gridGroupingColumnsModelSelector = createSelector( - gridGroupingColumnsStateSelector, - (groupingColumns) => groupingColumns.model, -); - -export const gridGroupingColumnsSanitizedModelSelector = createSelector( - gridGroupingColumnsModelSelector, - gridColumnLookupSelector, - (model, columnsLookup) => - model.filter((field) => !!columnsLookup[field] && columnsLookup[field].canBeGrouped), -); diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts b/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts deleted file mode 100644 index 52b8bf7b17a6a..0000000000000 --- a/packages/grid/_modules_/grid/hooks/features/groupingColumns/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './gridGroupingColumnsSelector'; -export * from './gridGroupingColumnsInterfaces'; diff --git a/packages/grid/_modules_/grid/hooks/features/index.ts b/packages/grid/_modules_/grid/hooks/features/index.ts index 0bd2576aa7172..dc5ac10f8aa97 100644 --- a/packages/grid/_modules_/grid/hooks/features/index.ts +++ b/packages/grid/_modules_/grid/hooks/features/index.ts @@ -13,4 +13,4 @@ export * from './rows'; export * from './selection'; export * from './sorting'; export * from './dimensions'; -export * from './groupingColumns'; +export * from './rowGrouping'; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx similarity index 95% rename from packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx rename to packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx index d18162e6fad85..bcbc5d0e38d7c 100644 --- a/packages/grid/_modules_/grid/hooks/features/groupingColumns/createGroupingColDef.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -12,8 +12,8 @@ import { import { GridColumnRawLookup } from '../columns/gridColumnsState'; import { GridGroupingCriteriaCell } from '../../../components/cell/GridGroupingCriteriaCell'; import { GridGroupingColumnLeafCell } from '../../../components/cell/GridGroupingColumnLeafCell'; -import { getGroupingColDefFieldFromGroupingCriteriaField } from './gridGroupingColumnsUtils'; -import { gridGroupingColumnsSanitizedModelSelector } from './gridGroupingColumnsSelector'; +import { getGroupingColDefFieldFromGroupingCriteriaField } from './gridRowGroupingUtils'; +import { gridRowGroupingSanitizedModelSelector } from './gridRowGroupingSelector'; const GROUPING_COL_DEF_DEFAULT_PROPERTIES: Omit = { ...GRID_STRING_COL_DEF, @@ -32,7 +32,7 @@ const GROUPING_COL_DEF_FORCED_PROPERTIES: Pick { - const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(cellParams1.api.state); + const model = gridRowGroupingSanitizedModelSelector(cellParams1.api.state); const groupingField1 = cellParams1.rowNode.groupingField; const groupingField2 = cellParams2.rowNode.groupingField; @@ -48,7 +48,7 @@ const groupingFieldIndexComparator: GridComparatorFn = (v1, v2, cellParams1, cel return 1; } - if (groupingColumnsModel.indexOf(groupingField1) < groupingColumnsModel.indexOf(groupingField2)) { + if (model.indexOf(groupingField1) < model.indexOf(groupingField2)) { return -1; } @@ -254,7 +254,7 @@ interface CreateGroupingColDefSeveralCriteriaParams { /** * The fields from which we are grouping the rows. */ - groupingColumnsModel: string[]; + rowGroupingModel: string[]; /** * The col def properties the user wants to override. @@ -269,7 +269,7 @@ interface CreateGroupingColDefSeveralCriteriaParams { export const createGroupingColDefForAllGroupingCriteria = ({ apiRef, columnsLookup, - groupingColumnsModel, + rowGroupingModel, colDefOverride, }: CreateGroupingColDefSeveralCriteriaParams): GridColDef => { const { leafField, mainGroupingCriteria, hideDescendantCount, ...colDefOverrideProperties } = @@ -280,7 +280,7 @@ export const createGroupingColDefForAllGroupingCriteria = ({ const commonProperties: Partial = { headerName: apiRef.current.getLocaleText('groupingColumnHeaderName'), width: Math.max( - ...groupingColumnsModel.map( + ...rowGroupingModel.map( (field) => (columnsLookup[field].width ?? GRID_STRING_COL_DEF.width!) + 40, ), leafColDef?.width ?? 0, @@ -333,14 +333,14 @@ export const createGroupingColDefForAllGroupingCriteria = ({ // // By default, we apply the sorting / filtering on the groups of the top level grouping criteria based on the properties of `columnsLookup[orderedGroupedByFields[0]]`. let sourceProperties: Partial; - if (mainGroupingCriteria && groupingColumnsModel.includes(mainGroupingCriteria)) { + if (mainGroupingCriteria && rowGroupingModel.includes(mainGroupingCriteria)) { sourceProperties = getGroupingCriteriaProperties(columnsLookup[mainGroupingCriteria], true); } else if (leafColDef) { sourceProperties = getLeafProperties(leafColDef); } else { sourceProperties = getGroupingCriteriaProperties( - columnsLookup[groupingColumnsModel[0]], - groupingColumnsModel.length === 1, + columnsLookup[rowGroupingModel[0]], + rowGroupingModel.length === 1, ); } diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts new file mode 100644 index 0000000000000..e121f28fdb0c2 --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts @@ -0,0 +1,37 @@ +export type GridRowGroupingModel = string[]; + +export interface GridRowGroupingState { + model: GridRowGroupingModel; +} + +export interface GridRowGroupingInitialState { + model?: GridRowGroupingModel; +} + +export interface GridRowGroupingApi { + /** + * Sets the columns to use as grouping criteria. + * @param {GridRowGroupingModel} model The columns to use as grouping criteria. + */ + setRowGroupingModel: (model: GridRowGroupingModel) => void; + + /** + * Add the field to the rowGroupingModel. + * @param {string} groupingCriteriaField The field from which we want to group the rows. + * @param {number | undefined} groupingIndex The grouping index at which we want to insert the new grouping criteria. By default, it will be inserted at the end of the model. + */ + addRowGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => void; + + /** + * Remove the field from to rowGroupingModel. + * @param {string} groupingCriteriaField The field from which we want to stop grouping the rows. + */ + removeRowGroupingCriteria: (groupingCriteriaField: string) => void; + + /** + * Sets the grouping index of a grouping criteria. + * @param {string} groupingCriteriaField The field of the grouping criteria from which we want to change the grouping index. + * @param {number} groupingIndex The new grouping index of this grouping criteria. + */ + setRowGroupingCriteriaIndex: (groupingCriteriaField: string, groupingIndex: number) => void; +} diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts new file mode 100644 index 0000000000000..dbd486fbb9ef2 --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts @@ -0,0 +1,17 @@ +import { createSelector } from 'reselect'; +import { GridState } from '../../../models'; +import { gridColumnLookupSelector } from '../columns'; + +export const gridRowGroupingStateSelector = (state: GridState) => state.rowGrouping; + +export const gridRowGroupingModelSelector = createSelector( + gridRowGroupingStateSelector, + (rowGrouping) => rowGrouping.model, +); + +export const gridRowGroupingSanitizedModelSelector = createSelector( + gridRowGroupingModelSelector, + gridColumnLookupSelector, + (model, columnsLookup) => + model.filter((field) => !!columnsLookup[field] && columnsLookup[field].canBeGrouped), +); diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts similarity index 100% rename from packages/grid/_modules_/grid/hooks/features/groupingColumns/gridGroupingColumnsUtils.ts rename to packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts new file mode 100644 index 0000000000000..387f4cae74ed4 --- /dev/null +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts @@ -0,0 +1,2 @@ +export * from './gridRowGroupingSelector'; +export * from './gridRowGroupingInterfaces'; diff --git a/packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx similarity index 75% rename from packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx rename to packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index f5ac1dc4bdd4d..34179e59fa697 100644 --- a/packages/grid/_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -14,9 +14,9 @@ import { useFirstRender } from '../../utils/useFirstRender'; import { buildRowTree, BuildRowTreeGroupingCriteria } from '../../../utils/tree/buildRowTree'; import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { - gridGroupingColumnsModelSelector, - gridGroupingColumnsSanitizedModelSelector, -} from './gridGroupingColumnsSelector'; + gridRowGroupingModelSelector, + gridRowGroupingSanitizedModelSelector, +} from './gridRowGroupingSelector'; import { GridComponentProps } from '../../../GridComponentProps'; import { filterRowTreeFromGroupingColumns, @@ -24,7 +24,7 @@ import { getColDefOverrides, GROUPING_COLUMNS_FEATURE_NAME, isGroupingColumn, -} from './gridGroupingColumnsUtils'; +} from './gridRowGroupingUtils'; import { createGroupingColDefForOneGroupingCriteria, createGroupingColDefForAllGroupingCriteria, @@ -40,66 +40,66 @@ import { GridSortingMethod } from '../sorting/gridSortingState'; import { sortRowTree } from '../../../utils/tree/sortRowTree'; import { gridFilteredDescendantCountLookupSelector } from '../filter'; import { useGridStateInit } from '../../utils/useGridStateInit'; -import { GridGroupingColumnsApi, GridGroupingColumnsModel } from './gridGroupingColumnsInterfaces'; +import { GridRowGroupingApi, GridRowGroupingModel } from './gridRowGroupingInterfaces'; import { useGridApiMethod } from '../../utils'; import { gridColumnLookupSelector } from '../columns'; -import { GridGroupingColumnsMenuItems } from '../../../components/menu/columnMenu/GridGroupingColumnsMenuItems'; +import { GridRowGroupingMenuItems } from '../../../components/menu/columnMenu/GridRowGroupingMenuItems'; /** * Only available in DataGridPro * @requires useGridColumns (state, method) - can be after, async only * @requires useGridRows (state, method) - can be after, async only * @requires useGridParamsApi (method) - can be after, async only - * TODO: Move the the Premium plan once available and remove the `experimentalFeatures.groupingColumns` flag + * TODO: Move the the Premium plan once available and remove the `experimentalFeatures.rowGrouping` flag */ -export const useGridGroupingColumns = ( +export const useGridRowGrouping = ( apiRef: GridApiRef, props: Pick< GridComponentProps, | 'initialState' - | 'groupingColumnsModel' - | 'onGroupingColumnsModelChange' + | 'rowGroupingModel' + | 'onRowGroupingModelChange' | 'defaultGroupingExpansionDepth' | 'groupingColDef' - | 'groupingColumnMode' - | 'disableGroupingColumns' + | 'rowGroupingColumnMode' + | 'disableRowGrouping' >, ) => { useGridStateInit(apiRef, (state) => ({ ...state, - groupingColumns: { - model: props.groupingColumnsModel ?? props.initialState?.groupingColumns?.model ?? [], + rowGrouping: { + model: props.rowGroupingModel ?? props.initialState?.rowGrouping?.model ?? [], }, })); apiRef.current.unstable_updateControlState({ - stateId: 'groupingColumns', - propModel: props.groupingColumnsModel, - propOnChange: props.onGroupingColumnsModelChange, - stateSelector: gridGroupingColumnsModelSelector, - changeEvent: GridEvents.groupingColumnsModelChange, + stateId: 'rowGrouping', + propModel: props.rowGroupingModel, + propOnChange: props.onRowGroupingModelChange, + stateSelector: gridRowGroupingModelSelector, + changeEvent: GridEvents.rowGroupingModelChange, }); /** * ROW GROUPING */ // Tracks the model on the last pre-processing to check if we need to re-build the grouping columns when the grid upserts a column. - const sanitizedModelOnLastRowPreProcessing = React.useRef([]); + const sanitizedModelOnLastRowPreProcessing = React.useRef([]); const updateRowGrouping = React.useCallback(() => { const groupRows: GridRowGroupingPreProcessing = (params) => { - const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(apiRef.current.state); + const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef.current.state); const columnsLookup = gridColumnLookupSelector(apiRef.current.state); - sanitizedModelOnLastRowPreProcessing.current = groupingColumnsModel; + sanitizedModelOnLastRowPreProcessing.current = rowGroupingModel; - if (props.disableGroupingColumns || groupingColumnsModel.length === 0) { + if (props.disableRowGrouping || rowGroupingModel.length === 0) { return null; } const distinctValues: { [field: string]: { lookup: { [val: string]: boolean }; list: any[] }; } = Object.fromEntries( - groupingColumnsModel.map((groupingField) => [groupingField, { lookup: {}, list: [] }]), + rowGroupingModel.map((groupingField) => [groupingField, { lookup: {}, list: [] }]), ); const getCellGroupingCriteria = ({ @@ -148,7 +148,7 @@ export const useGridGroupingColumns = ( params.ids.forEach((rowId) => { const row = params.idRowsLookup[rowId]; - groupingColumnsModel.forEach((groupingCriteria) => { + rowGroupingModel.forEach((groupingCriteria) => { const { key } = getCellGroupingCriteria({ row, id: rowId, @@ -165,7 +165,7 @@ export const useGridGroupingColumns = ( const rows = params.ids.map((rowId) => { const row = params.idRowsLookup[rowId]; - const parentPath = groupingColumnsModel + const parentPath = rowGroupingModel .map((groupingField) => getCellGroupingCriteria({ row, @@ -195,7 +195,7 @@ export const useGridGroupingColumns = ( }; return apiRef.current.unstable_registerRowGroupsBuilder('rowGrouping', groupRows); - }, [apiRef, props.defaultGroupingExpansionDepth, props.disableGroupingColumns]); + }, [apiRef, props.defaultGroupingExpansionDepth, props.disableRowGrouping]); useFirstRender(() => { updateRowGrouping(); @@ -216,35 +216,35 @@ export const useGridGroupingColumns = ( */ const getGroupingColDefs = React.useCallback( (columnsState: GridColumnsRawState) => { - if (props.disableGroupingColumns) { + if (props.disableRowGrouping) { return []; } const propGroupingColDef = props.groupingColDef; // We can't use `gridGroupingRowsSanitizedModelSelector` here because the new columns are not in the state yet - const groupingColumnsModel = gridGroupingColumnsModelSelector(apiRef.current.state).filter( + const rowGroupingModel = gridRowGroupingModelSelector(apiRef.current.state).filter( (field) => !!columnsState.lookup[field], ); - if (groupingColumnsModel.length === 0) { + if (rowGroupingModel.length === 0) { return []; } - switch (props.groupingColumnMode) { + switch (props.rowGroupingColumnMode) { case 'single': { return [ createGroupingColDefForAllGroupingCriteria({ apiRef, - groupingColumnsModel, - colDefOverride: getColDefOverrides(propGroupingColDef, groupingColumnsModel), + rowGroupingModel, + colDefOverride: getColDefOverrides(propGroupingColDef, rowGroupingModel), columnsLookup: columnsState.lookup, }), ]; } case 'multiple': { - return groupingColumnsModel.map((groupingCriteria) => + return rowGroupingModel.map((groupingCriteria) => createGroupingColDefForOneGroupingCriteria({ groupingCriteria, colDefOverride: getColDefOverrides(propGroupingColDef, [groupingCriteria]), @@ -259,7 +259,7 @@ export const useGridGroupingColumns = ( } } }, - [apiRef, props.groupingColDef, props.groupingColumnMode, props.disableGroupingColumns], + [apiRef, props.groupingColDef, props.rowGroupingColumnMode, props.disableRowGrouping], ); const updateGroupingColumn = React.useCallback( @@ -295,13 +295,13 @@ export const useGridGroupingColumns = ( const addColumnMenuButtons = React.useCallback( (initialValue: JSX.Element[]) => { - if (props.disableGroupingColumns) { + if (props.disableRowGrouping) { return initialValue; } - return [...initialValue, ]; + return [...initialValue, ]; }, - [props.disableGroupingColumns], + [props.disableRowGrouping], ); const filteringMethod = React.useCallback( @@ -340,15 +340,13 @@ export const useGridGroupingColumns = ( /** * API METHODS */ - const setGroupingColumnsModel = React.useCallback< - GridGroupingColumnsApi['setGroupingColumnsModel'] - >( + const setRowGroupingModel = React.useCallback( (model) => { - const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + const currentModel = gridRowGroupingModelSelector(apiRef.current.state); if (currentModel !== model) { apiRef.current.setState((state) => ({ ...state, - groupingColumns: { ...state.groupingColumns, model }, + rowGrouping: { ...state.rowGrouping, model }, })); updateRowGrouping(); apiRef.current.forceUpdate(); @@ -357,9 +355,9 @@ export const useGridGroupingColumns = ( [apiRef, updateRowGrouping], ); - const addGroupingCriteria = React.useCallback( + const addRowGroupingCriteria = React.useCallback( (field, groupingIndex) => { - const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + const currentModel = gridRowGroupingModelSelector(apiRef.current.state); if (currentModel.includes(field)) { return; } @@ -372,29 +370,29 @@ export const useGridGroupingColumns = ( ...currentModel.slice(cleanGroupingIndex), ]; - apiRef.current.setGroupingColumnsModel(updatedModel); + apiRef.current.setRowGroupingModel(updatedModel); }, [apiRef], ); - const removeGroupingCriteria = React.useCallback< - GridGroupingColumnsApi['removeGroupingCriteria'] + const removeRowGroupingCriteria = React.useCallback< + GridRowGroupingApi['removeRowGroupingCriteria'] >( (field) => { - const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + const currentModel = gridRowGroupingModelSelector(apiRef.current.state); if (!currentModel.includes(field)) { return; } - apiRef.current.setGroupingColumnsModel(currentModel.filter((el) => el !== field)); + apiRef.current.setRowGroupingModel(currentModel.filter((el) => el !== field)); }, [apiRef], ); - const setGroupingCriteriaIndex = React.useCallback< - GridGroupingColumnsApi['setGroupingCriteriaIndex'] + const setRowGroupingCriteriaIndex = React.useCallback< + GridRowGroupingApi['setRowGroupingCriteriaIndex'] >( (field, targetIndex) => { - const currentModel = gridGroupingColumnsModelSelector(apiRef.current.state); + const currentModel = gridRowGroupingModelSelector(apiRef.current.state); const currentTargetIndex = currentModel.indexOf(field); if (currentTargetIndex === -1) { @@ -404,20 +402,20 @@ export const useGridGroupingColumns = ( const updatedModel = [...currentModel]; updatedModel.splice(targetIndex, 0, updatedModel.splice(currentTargetIndex, 1)[0]); - apiRef.current.setGroupingColumnsModel(updatedModel); + apiRef.current.setRowGroupingModel(updatedModel); }, [apiRef], ); - useGridApiMethod( + useGridApiMethod( apiRef, { - setGroupingColumnsModel, - addGroupingCriteria, - removeGroupingCriteria, - setGroupingCriteriaIndex, + setRowGroupingModel, + addRowGroupingCriteria, + removeRowGroupingCriteria, + setRowGroupingCriteriaIndex, }, - 'GridGroupingColumnsApi', + 'GridRowGroupingApi', ); /** @@ -434,7 +432,7 @@ export const useGridGroupingColumns = ( gridFilteredDescendantCountLookupSelector(apiRef.current.state)[params.id] ?? 0; const isOnGroupingCell = - props.groupingColumnMode === 'single' || + props.rowGroupingColumnMode === 'single' || getGroupingColDefFieldFromGroupingCriteriaField(params.rowNode.groupingField) === params.field; if (!isOnGroupingCell || filteredDescendantCount === 0) { @@ -444,17 +442,17 @@ export const useGridGroupingColumns = ( apiRef.current.setRowChildrenExpansion(params.id, !params.rowNode.childrenExpanded); } }, - [apiRef, props.groupingColumnMode], + [apiRef, props.rowGroupingColumnMode], ); const checkGroupingColumnsModelDiff = React.useCallback< GridEventListener >(() => { - const groupingColumnsModel = gridGroupingColumnsSanitizedModelSelector(apiRef.current.state); + const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef.current.state); const lastGroupingColumnsModelApplied = sanitizedModelOnLastRowPreProcessing.current; - if (!isDeepEqual(lastGroupingColumnsModelApplied, groupingColumnsModel)) { - sanitizedModelOnLastRowPreProcessing.current = groupingColumnsModel; + if (!isDeepEqual(lastGroupingColumnsModelApplied, rowGroupingModel)) { + sanitizedModelOnLastRowPreProcessing.current = rowGroupingModel; // Refresh the column pre-processing apiRef.current.updateColumns([]); @@ -464,18 +462,14 @@ export const useGridGroupingColumns = ( useGridApiEventHandler(apiRef, GridEvents.cellKeyDown, handleCellKeyDown); useGridApiEventHandler(apiRef, GridEvents.columnsChange, checkGroupingColumnsModelDiff); - useGridApiEventHandler( - apiRef, - GridEvents.groupingColumnsModelChange, - checkGroupingColumnsModelDiff, - ); + useGridApiEventHandler(apiRef, GridEvents.rowGroupingModelChange, checkGroupingColumnsModelDiff); /** * EFFECTS */ React.useEffect(() => { - if (props.groupingColumnsModel !== undefined) { - apiRef.current.setGroupingColumnsModel(props.groupingColumnsModel); + if (props.rowGroupingModel !== undefined) { + apiRef.current.setRowGroupingModel(props.rowGroupingModel); } - }, [apiRef, props.groupingColumnsModel]); + }, [apiRef, props.rowGroupingModel]); }; diff --git a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts index 600c1861e16d3..951a0f2792b72 100644 --- a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts +++ b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts @@ -107,8 +107,7 @@ export const useGridProcessedProps = (inProps: GridInputComponentProps) => { () => ({ ...GRID_DEFAULT_SIMPLE_OPTIONS, ...inProps, - disableGroupingColumns: - inProps.disableGroupingColumns || !inProps.experimentalFeatures?.groupingColumns, + disableRowGrouping: inProps.disableRowGrouping || !inProps.experimentalFeatures?.rowGrouping, localeText, components, }), diff --git a/packages/grid/_modules_/grid/models/api/gridApi.ts b/packages/grid/_modules_/grid/models/api/gridApi.ts index c27bbfa5ca2af..95084fa547ad2 100644 --- a/packages/grid/_modules_/grid/models/api/gridApi.ts +++ b/packages/grid/_modules_/grid/models/api/gridApi.ts @@ -22,7 +22,7 @@ import { GridColumnPinningApi } from './gridColumnPinningApi'; import type { GridPreProcessingApi } from '../../hooks/core/preProcessing'; import type { GridRowGroupsPreProcessingApi } from '../../hooks/core/rowGroupsPerProcessing'; import type { GridDimensionsApi } from '../../hooks/features/dimensions'; -import type { GridGroupingColumnsApi } from '../../hooks/features/groupingColumns'; +import type { GridRowGroupingApi } from '../../hooks/features/rowGrouping'; import type { GridPaginationApi } from '../../hooks/features/pagination'; /** @@ -53,5 +53,5 @@ export interface GridApi GridLocaleTextApi, GridClipboardApi, GridScrollApi, - GridGroupingColumnsApi, + GridRowGroupingApi, GridColumnPinningApi {} diff --git a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts index 0314bdd620433..0ad3910165098 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts @@ -257,7 +257,7 @@ export interface GridGroupingColDefOverride > { /** * The field from which we want to apply the sorting and the filtering for the grouping column. - * It is only useful when `props.groupingColumnMode === "multiple"` to decide which grouping criteria should be used for sorting and filtering. + * It is only useful when `props.rowGroupingColumnMode === "multiple"` to decide which grouping criteria should be used for sorting and filtering. * Do not have any effect when building the tree with the `props.treeData` feature. * @default: The sorting and filtering is applied based on the leaf field in any, otherwise based on top level grouping criteria. */ diff --git a/packages/grid/_modules_/grid/models/events/gridEventLookup.ts b/packages/grid/_modules_/grid/models/events/gridEventLookup.ts index 7fe6cd86af493..02f5941d0e97e 100644 --- a/packages/grid/_modules_/grid/models/events/gridEventLookup.ts +++ b/packages/grid/_modules_/grid/models/events/gridEventLookup.ts @@ -22,7 +22,7 @@ import type { ElementSize } from '../elementSize'; import type { MuiBaseEvent } from '../muiEvent'; import type { GridRowId, GridRowTreeNodeConfig } from '../gridRows'; import type { GridPreProcessingGroup } from '../../hooks/core/preProcessing'; -import type { GridGroupingColumnsModel } from '../../hooks/features/groupingColumns'; +import type { GridRowGroupingModel } from '../../hooks/features/rowGrouping'; import type { GridPinnedColumns } from '../api/gridColumnPinningApi'; export interface GridRowEventLookup { @@ -129,7 +129,7 @@ export interface GridControlledStateEventLookup { sortModelChange: { params: GridSortModel }; editRowsModelChange: { params: GridEditRowsModel }; selectionChange: { params: GridSelectionModel }; - groupingColumnsModelChange: { params: GridGroupingColumnsModel }; + rowGroupingModelChange: { params: GridRowGroupingModel }; pinnedColumnsChange: { params: GridPinnedColumns }; } diff --git a/packages/grid/_modules_/grid/models/events/gridEvents.ts b/packages/grid/_modules_/grid/models/events/gridEvents.ts index c85505bdad9a3..157518db82eb4 100644 --- a/packages/grid/_modules_/grid/models/events/gridEvents.ts +++ b/packages/grid/_modules_/grid/models/events/gridEvents.ts @@ -206,9 +206,9 @@ export enum GridEvents { */ pageSizeChange = 'pageSizeChange', /** - * Fired when the grouping columns model changes. + * Fired when the row grouping model changes. */ - groupingColumnsModelChange = 'groupingColumnsModelChange', + rowGroupingModelChange = 'rowGroupingModelChange', /** * Fired during the scroll of the grid viewport. */ diff --git a/packages/grid/_modules_/grid/models/gridOptions.tsx b/packages/grid/_modules_/grid/models/gridOptions.tsx index 499a9f90f7555..61abe6ed65e26 100644 --- a/packages/grid/_modules_/grid/models/gridOptions.tsx +++ b/packages/grid/_modules_/grid/models/gridOptions.tsx @@ -15,7 +15,7 @@ export enum GridExperimentalFeatures { * Only available on the Pro plan. * Will be part of the premium-plan when fully ready. */ - groupingColumns = 'groupingColumns', + rowGrouping = 'rowGrouping', } /** @@ -165,7 +165,7 @@ export interface GridSimpleOptions { * If `true`, the grouping columns are disabled. * @default false */ - disableGroupingColumns: boolean; + disableRowGrouping: boolean; /** * Controls whether to use the cell or row editing. * @default "cell" @@ -245,7 +245,7 @@ export interface GridSimpleOptions { * If `multiple`, each column we are grouping by will be represented in its own column. * @default 'single' */ - groupingColumnMode: 'single' | 'multiple'; + rowGroupingColumnMode: 'single' | 'multiple'; /** * If above 0, the row children will be expanded up to this depth. * If equal to -1, all the row children will be expanded. @@ -315,7 +315,7 @@ export const GRID_DEFAULT_SIMPLE_OPTIONS: GridSimpleOptions = { disableChildrenSorting: false, disableSelectionOnClick: false, disableVirtualization: false, - disableGroupingColumns: false, + disableRowGrouping: false, editMode: GridEditModes.Cell, filterMode: GridFeatureModeConstant.client, headerHeight: 56, @@ -330,7 +330,7 @@ export const GRID_DEFAULT_SIMPLE_OPTIONS: GridSimpleOptions = { rowHeight: 52, rowsPerPageOptions: [25, 50, 100], treeData: false, - groupingColumnMode: 'single', + rowGroupingColumnMode: 'single', defaultGroupingExpansionDepth: 0, scrollEndThreshold: 80, showCellRightBorder: false, diff --git a/packages/grid/_modules_/grid/models/gridState.ts b/packages/grid/_modules_/grid/models/gridState.ts index 740581083702f..e22902850e21c 100644 --- a/packages/grid/_modules_/grid/models/gridState.ts +++ b/packages/grid/_modules_/grid/models/gridState.ts @@ -21,9 +21,9 @@ import type { GridFilterInitialState, } from '../hooks/features/filter/gridFilterState'; import type { - GridGroupingColumnsState, - GridGroupingColumnsInitialState, -} from '../hooks/features/groupingColumns'; + GridRowGroupingState, + GridRowGroupingInitialState, +} from '../hooks/features/rowGrouping'; import { GridColumnPinningState } from '../hooks/features/columnPinning/gridColumnPinningState'; /** @@ -44,7 +44,7 @@ export interface GridState { filter: GridFilterState; preferencePanel: GridPreferencePanelState; density: GridDensityState; - groupingColumns: GridGroupingColumnsState; + rowGrouping: GridRowGroupingState; error?: any; pinnedColumns: GridColumnPinningState; } @@ -53,6 +53,6 @@ export interface GridInitialState { sorting?: GridSortingInitialState; filter?: GridFilterInitialState; preferencePanel?: GridPreferencePanelInitialState; - groupingColumns?: GridGroupingColumnsInitialState; + rowGrouping?: GridRowGroupingInitialState; pinnedColumns?: GridColumnPinningState; } diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx index b7fa7cfc48fe2..c0efb624a471d 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx @@ -196,11 +196,6 @@ DataGridProRaw.propTypes = { * @default false */ disableExtendRowFullWidth: PropTypes.bool, - /** - * If `true`, the grouping columns are disabled. - * @default false - */ - disableGroupingColumns: PropTypes.bool, /** * If `true`, filtering with multiple columns is disabled. * @default false @@ -216,6 +211,11 @@ DataGridProRaw.propTypes = { * @default false */ disableMultipleSelection: PropTypes.bool, + /** + * If `true`, the grouping columns are disabled. + * @default false + */ + disableRowGrouping: PropTypes.bool, /** * If `true`, the selection on click on a row or cell is disabled. * @default false @@ -244,7 +244,7 @@ DataGridProRaw.propTypes = { * For each feature, if the flag is not explicitly set to `true`, the feature will be fully disabled and any property / method call will not have any effect. */ experimentalFeatures: PropTypes.shape({ - groupingColumns: PropTypes.bool, + rowGrouping: PropTypes.bool, }), /** * Filtering can be processed on the server or client-side. @@ -301,16 +301,6 @@ DataGridProRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - /** - * If `single`, all column we are grouping by will be represented in the same grouping the same column. - * If `multiple`, each column we are grouping by will be represented in its own column. - * @default 'single' - */ - groupingColumnMode: PropTypes.oneOf(['multiple', 'single']), - /** - * Set the grouping columns of the grid. - */ - groupingColumnsModel: PropTypes.arrayOf(PropTypes.string), /** * Set the height in pixel of the column headers in the grid. * @default 56 @@ -534,12 +524,6 @@ DataGridProRaw.propTypes = { * @param {GridCallbackDetails} details Additional details for this callback. */ onFilterModelChange: PropTypes.func, - /** - * Callback fired when the grouping columns model changes. - * @param {GridGroupingColumnsModel} model Columns used as grouping criteria. - * @param {GridCallbackDetails} details Additional details for this callback. - */ - onGroupingColumnsModelChange: PropTypes.func, /** * Callback fired when the current page has changed. * @param {number} page Index of the page displayed on the Grid. @@ -597,6 +581,12 @@ DataGridProRaw.propTypes = { * @param {MuiEvent} event The event that caused this prop to be called. */ onRowEditStop: PropTypes.func, + /** + * Callback fired when the grouping columns model changes. + * @param {GridRowGroupingModel} model Columns used as grouping criteria. + * @param {GridCallbackDetails} details Additional details for this callback. + */ + onRowGroupingModelChange: PropTypes.func, /** * Callback fired when scrolling to the bottom of the grid viewport. * @param {GridRowScrollEndParams} params With all properties from [[GridRowScrollEndParams]]. @@ -664,6 +654,16 @@ DataGridProRaw.propTypes = { * If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows. */ rowCount: PropTypes.number, + /** + * If `single`, all column we are grouping by will be represented in the same grouping the same column. + * If `multiple`, each column we are grouping by will be represented in its own column. + * @default 'single' + */ + rowGroupingColumnMode: PropTypes.oneOf(['multiple', 'single']), + /** + * Set the grouping columns of the grid. + */ + rowGroupingModel: PropTypes.arrayOf(PropTypes.string), /** * Set the height in pixel of a row in the grid. * @default 52 diff --git a/packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx similarity index 82% rename from packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx rename to packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index be5649d16e1c8..6149892c696c1 100644 --- a/packages/grid/x-data-grid-pro/src/tests/groupingColumns.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -50,7 +50,7 @@ const baselineProps: DataGridProProps = { }, ], experimentalFeatures: { - groupingColumns: true, + rowGrouping: true, }, }; @@ -70,11 +70,11 @@ describe(' - Group Rows By Column', () => { }; describe('Setting grouping criteria', () => { - describe('initialState: groupingColumns.model', () => { + describe('initialState: rowGrouping.model', () => { it('should allow to initialize the grouping columns', () => { render( , ); @@ -84,42 +84,42 @@ describe(' - Group Rows By Column', () => { it('should not react to initial state updates', () => { const { setProps } = render( , ); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); - setProps({ initialState: { groupingColumns: { model: ['category2'] } } }); + setProps({ initialState: { rowGrouping: { model: ['category2'] } } }); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); }); }); - describe('prop: groupingColumnsModel', () => { - it('should not call onGroupingColumnsModelChange on initialisation or on groupingColumnsModel prop change', () => { - const onGroupingColumnsModelChange = spy(); + describe('prop: rowGroupingModel', () => { + it('should not call onRowGroupingModelChange on initialisation or on rowGroupingModel prop change', () => { + const onRowGroupingModelChange = spy(); const { setProps } = render( , ); - expect(onGroupingColumnsModelChange.callCount).to.equal(0); - setProps({ groupingColumnsModel: ['category2'] }); + expect(onRowGroupingModelChange.callCount).to.equal(0); + setProps({ rowGroupingModel: ['category2'] }); - expect(onGroupingColumnsModelChange.callCount).to.equal(0); + expect(onRowGroupingModelChange.callCount).to.equal(0); }); - it('should allow to update the grouping columns model from the outside', () => { + it('should allow to update the row grouping model from the outside', () => { const { setProps } = render( - , + , ); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); - setProps({ groupingColumnsModel: ['category2'] }); - expect(getColumnValues()).to.deep.equal(['Cat 1 (2)', '', '', 'Cat 2 (3)', '', '', '']); - setProps({ groupingColumnsModel: ['category1', 'category2'] }); + setProps({ rowGroupingModel: ['category2'] }); + expect(getColumnValues(0)).to.deep.equal(['Cat 1 (2)', '', '', 'Cat 2 (3)', '', '', '']); + setProps({ rowGroupingModel: ['category1', 'category2'] }); expect(getColumnValues()).to.deep.equal([ 'Cat A (3)', 'Cat 1 (1)', @@ -139,7 +139,7 @@ describe(' - Group Rows By Column', () => { it('should ignore grouping criteria that do not match any column', () => { render( , ); @@ -162,7 +162,7 @@ describe(' - Group Rows By Column', () => { canBeGrouped: false, }, ]} - initialState={{ groupingColumns: { model: ['category1', 'category2'] } }} + initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} defaultGroupingExpansionDepth={-1} />, ); @@ -172,7 +172,7 @@ describe(' - Group Rows By Column', () => { it('should allow to use several time the same grouping criteria', () => { render( , ); @@ -191,11 +191,11 @@ describe(' - Group Rows By Column', () => { }); }); - describe('props: groupingColumnMode', () => { - it('should gather all the grouping criteria into a single column when groupingColumnMode is not defined', () => { + describe('props: rowGroupingColumnMode', () => { + it('should gather all the grouping criteria into a single column when rowGroupingColumnMode is not defined', () => { render( , ); @@ -221,12 +221,12 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should gather all the grouping criteria into a single column when groupingColumnMode = "single"', () => { + it('should gather all the grouping criteria into a single column when rowGroupingColumnMode = "single"', () => { render( , ); @@ -251,12 +251,12 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should create one grouping column per grouping criteria when groupingColumnMode = "multiple"', () => { + it('should create one grouping column per grouping criteria when rowGroupingColumnMode = "multiple"', () => { render( , ); @@ -295,12 +295,12 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should support groupingColumnMode switch', () => { + it('should support rowGroupingColumnMode switch', () => { const { setProps } = render( , ); @@ -338,7 +338,7 @@ describe(' - Group Rows By Column', () => { '', ]); - setProps({ groupingColumnMode: 'single' }); + setProps({ rowGroupingColumnMode: 'single' }); expect(getColumnHeadersTextContent()).to.deep.equal([ 'Group', 'id', @@ -359,7 +359,7 @@ describe(' - Group Rows By Column', () => { '', ]); - setProps({ groupingColumnMode: 'multiple' }); + setProps({ rowGroupingColumnMode: 'multiple' }); expect(getColumnHeadersTextContent()).to.deep.equal([ 'category1', 'category2', @@ -395,12 +395,12 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should respect the model grouping order when groupingColumnMode = "single"', () => { + it('should respect the model grouping order when rowGroupingColumnMode = "single"', () => { render( , ); @@ -425,12 +425,12 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should respect the model grouping order when groupingColumnMode = "multiple"', () => { + it('should respect the model grouping order when rowGroupingColumnMode = "multiple"', () => { render( , ); @@ -470,37 +470,37 @@ describe(' - Group Rows By Column', () => { }); }); - describe('props: disableGroupingColumns', () => { + describe('props: disableRowGrouping', () => { // TODO: Remove once the feature is stable - it('should set `disableGroupingColumns` to `true` if `experimentalFeatures.groupingColumns = false', () => { - const disableGroupingColumnsSpy = spy(); + it('should set `disableRowGrouping` to `true` if `experimentalFeatures.rowGrouping = false', () => { + const disableRowGroupingSpy = spy(); const CustomToolbar = () => { const rootProps = useGridRootProps(); - disableGroupingColumnsSpy(rootProps.disableGroupingColumns); + disableRowGroupingSpy(rootProps.disableRowGrouping); return null; }; render( , ); - expect(disableGroupingColumnsSpy.lastCall.firstArg).to.equal(true); + expect(disableRowGroupingSpy.lastCall.firstArg).to.equal(true); }); - it('should disable grouping columns when `prop.disableGroupingColumns = true`', () => { + it('should disable grouping columns when `prop.disableRowGrouping = true`', () => { render( , ); @@ -537,7 +537,7 @@ describe(' - Group Rows By Column', () => { render( , ); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); @@ -547,7 +547,7 @@ describe(' - Group Rows By Column', () => { render( , ); expect(getColumnValues(0)).to.deep.equal([ @@ -564,7 +564,7 @@ describe(' - Group Rows By Column', () => { render( , ); expect(getColumnValues(0)).to.deep.equal([ @@ -586,7 +586,7 @@ describe(' - Group Rows By Column', () => { render( , ); expect(getColumnValues(0)).to.deep.equal([ @@ -608,7 +608,7 @@ describe(' - Group Rows By Column', () => { const { setProps } = render( , ); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); @@ -625,7 +625,7 @@ describe(' - Group Rows By Column', () => { it('should not re-apply default expansion on rerender after expansion manually toggled', () => { const { setProps } = render( - , + , ); expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); act(() => { @@ -651,8 +651,8 @@ describe(' - Group Rows By Column', () => { it('should not allow to override the field', () => { const { setProps } = render( params.fields.includes('category1') ? { @@ -694,8 +694,8 @@ describe(' - Group Rows By Column', () => { it('should render the leafField `value` on leaves', () => { render( , @@ -731,8 +731,8 @@ describe(' - Group Rows By Column', () => { field: 'category1', }, ]} - initialState={{ groupingColumns: { model: ['category1'] } }} - groupingColumnMode="single" + initialState={{ rowGrouping: { model: ['category1'] } }} + rowGroupingColumnMode="single" groupingColDef={{ leafField: 'id' }} defaultGroupingExpansionDepth={-1} />, @@ -764,8 +764,8 @@ describe(' - Group Rows By Column', () => { field: 'category1', }, ]} - initialState={{ groupingColumns: { model: ['category1'] } }} - groupingColumnMode="single" + initialState={{ rowGrouping: { model: ['category1'] } }} + rowGroupingColumnMode="single" groupingColDef={{ leafField: 'id' }} defaultGroupingExpansionDepth={-1} />, @@ -789,8 +789,8 @@ describe(' - Group Rows By Column', () => { it('should allow to override the headerName in object mode', () => { render( - Group Rows By Column', () => { it('should allow to override the headerName in callback mode', () => { render( params.fields.includes('category1') ? { @@ -833,8 +833,8 @@ describe(' - Group Rows By Column', () => { it('should render descendant count when hideDescendantCount = false', () => { render( , @@ -858,8 +858,8 @@ describe(' - Group Rows By Column', () => { it('should not render descendant count when hideDescendantCount = true', () => { render( , @@ -886,8 +886,8 @@ describe(' - Group Rows By Column', () => { it('should not allow to override the field', () => { render( - Group Rows By Column', () => { it('should render the leafField `value` on leaves', () => { render( params.fields.includes('category2') ? { @@ -964,8 +964,8 @@ describe(' - Group Rows By Column', () => { field: 'category2', }, ]} - initialState={{ groupingColumns: { model: ['category1', 'category2'] } }} - groupingColumnMode="multiple" + initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} + rowGroupingColumnMode="multiple" groupingColDef={(params) => params.fields.includes('category2') ? { @@ -1023,8 +1023,8 @@ describe(' - Group Rows By Column', () => { field: 'category2', }, ]} - initialState={{ groupingColumns: { model: ['category1', 'category2'] } }} - groupingColumnMode="multiple" + initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} + rowGroupingColumnMode="multiple" groupingColDef={(params) => params.fields.includes('category2') ? { @@ -1071,8 +1071,8 @@ describe(' - Group Rows By Column', () => { it('should allow to override the headerName in object mode', () => { render( - Group Rows By Column', () => { it('should allow to override the headerName in callback mode', () => { render( params.fields.includes('category1') ? { @@ -1117,8 +1117,8 @@ describe(' - Group Rows By Column', () => { it('should render descendant count when hideDescendantCount = false', () => { render( , @@ -1155,8 +1155,8 @@ describe(' - Group Rows By Column', () => { it('should not render descendant count when hideDescendantCount = true', () => { render( , @@ -1205,7 +1205,7 @@ describe(' - Group Rows By Column', () => { keyGetter: (params: GridKeyGetterParams) => `key ${params.value}`, }, ]} - initialState={{ groupingColumns: { model: ['category1'] } }} + initialState={{ rowGrouping: { model: ['category1'] } }} defaultGroupingExpansionDepth={-1} />, ); @@ -1233,7 +1233,7 @@ describe(' - Group Rows By Column', () => { valueGetter: (params) => `value ${params.row.category1}`, }, ]} - initialState={{ groupingColumns: { model: ['complexCategory1'] } }} + initialState={{ rowGrouping: { model: ['complexCategory1'] } }} defaultGroupingExpansionDepth={-1} />, ); @@ -1253,7 +1253,7 @@ describe(' - Group Rows By Column', () => { render( - Group Rows By Column', () => { expect(screen.queryByRole('menu')).not.to.equal(null); const menuItem = screen.queryByRole('menuitem', { name: 'Group by category1' }); fireEvent.click(menuItem); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category1']); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category1']); }); it('should not add a "Group by {field}" menu item on ungrouped columns when coLDef.canBeGrouped = false', () => { @@ -1336,7 +1336,7 @@ describe(' - Group Rows By Column', () => { }, ]} initialState={{ - groupingColumns: { + rowGrouping: { model: ['category1'], }, }} @@ -1347,10 +1347,10 @@ describe(' - Group Rows By Column', () => { expect(screen.queryByRole('menu')).not.to.equal(null); const menuItem = screen.queryByRole('menuitem', { name: 'Stop grouping by category1' }); fireEvent.click(menuItem); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal([]); }); - it('should add a "Stop grouping by {field} menu item on each grouping column when prop.groupingColumnMode = "multiple"', () => { + it('should add a "Stop grouping by {field} menu item on each grouping column when prop.rowGroupingColumnMode = "multiple"', () => { render( - Group Rows By Column', () => { }, ]} initialState={{ - groupingColumns: { + rowGrouping: { model: ['category1', 'category2'], }, }} - groupingColumnMode="multiple" + rowGroupingColumnMode="multiple" />, ); @@ -1380,7 +1380,7 @@ describe(' - Group Rows By Column', () => { name: 'Stop grouping by category1', }); fireEvent.click(menuItemCategory1); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2']); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category2']); apiRef.current.hideColumnMenu(); clock.runToLast(); @@ -1393,10 +1393,10 @@ describe(' - Group Rows By Column', () => { name: 'Stop grouping by category2', }); fireEvent.click(menuItemCategory2); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal([]); }); - it('should add a "Stop grouping {field} menu item for each grouping criteria on the grouping column when prop.groupingColumnMode = "single"', () => { + it('should add a "Stop grouping {field} menu item for each grouping criteria on the grouping column when prop.rowGroupingColumnMode = "single"', () => { render( - Group Rows By Column', () => { }, ]} initialState={{ - groupingColumns: { + rowGrouping: { model: ['category1', 'category2'], }, }} - groupingColumnMode="single" + rowGroupingColumnMode="single" />, ); @@ -1426,12 +1426,12 @@ describe(' - Group Rows By Column', () => { name: 'Stop grouping by category1', }); fireEvent.click(menuItemCategory1); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2']); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category2']); const menuItemCategory2 = screen.queryByRole('menuitem', { name: 'Stop grouping by category2', }); fireEvent.click(menuItemCategory2); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal([]); }); it('should use the colDef.headerName property for grouping menu item label', () => { @@ -1467,7 +1467,7 @@ describe(' - Group Rows By Column', () => { }, ]} initialState={{ - groupingColumns: { + rowGrouping: { model: ['category1'], }, }} @@ -1483,12 +1483,12 @@ describe(' - Group Rows By Column', () => { }); describe('sorting', () => { - describe('props: groupingColumnMode = "single"', () => { + describe('props: rowGroupingColumnMode = "single"', () => { it('should use the top level grouping criteria for sorting if mainGroupingCriteria and leafField are not defined', () => { render( , @@ -1512,8 +1512,8 @@ describe(' - Group Rows By Column', () => { it('should use the column grouping criteria for sorting if mainGroupingCriteria is one of the grouping criteria and leaf field is defined', () => { render( - Group Rows By Column', () => { it('should use the leaf field for sorting if mainGroupingCriteria is not defined and leaf field is defined', () => { render( - Group Rows By Column', () => { it('should use the leaf field for sorting if mainGroupingCriteria is not one of the grouping criteria and leaf field is defined', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { }); }); - describe('props: groupingColumnMode = "multiple"', () => { + describe('props: rowGroupingColumnMode = "multiple"', () => { it('should use the column grouping criteria for sorting if mainGroupingCriteria and leafField are not defined', () => { render( , @@ -1660,8 +1660,8 @@ describe(' - Group Rows By Column', () => { it('should use the column grouping criteria for sorting if mainGroupingCriteria matches the column grouping criteria and leaf field is defined', () => { render( - Group Rows By Column', () => { it('should use the leaf field for sorting if mainGroupingCriteria is not defined and leaf field is defined', () => { render( - Group Rows By Column', () => { it("should use the leaf field for sorting if mainGroupingCriteria doesn't match the column grouping criteria and leaf field is defined", () => { render( - Group Rows By Column', () => { describe('filtering', () => { clock.withFakeTimers(); - describe('props: groupingColumnMode = "single"', () => { + describe('props: rowGroupingColumnMode = "single"', () => { it('should use the top level grouping criteria for filtering if mainGroupingCriteria and leafField are not defined', () => { render( , ); @@ -1768,10 +1768,10 @@ describe(' - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { }); }); - describe('props: groupingColumnMode = "multiple"', () => { + describe('props: rowGroupingColumnMode = "multiple"', () => { it('should use the column grouping criteria for filtering if mainGroupingCriteria and leafField are not defined', () => { render( , ); @@ -1895,10 +1895,10 @@ describe(' - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { render( - Group Rows By Column', () => { }, }, }} - groupingColumnMode="multiple" + rowGroupingColumnMode="multiple" defaultGroupingExpansionDepth={-1} />, ); @@ -2018,33 +2018,33 @@ describe(' - Group Rows By Column', () => { }); }); - describe('apiRef: addGroupingCriteria', () => { + describe('apiRef: addRowGroupingCriteria', () => { it('should add grouping criteria to model', () => { - render(); - apiRef.current.addGroupingCriteria('category2'); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category1', 'category2']); + render(); + apiRef.current.addRowGroupingCriteria('category2'); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category1', 'category2']); }); it('should add grouping criteria to model at the right position', () => { - render(); - apiRef.current.addGroupingCriteria('category2', 0); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2', 'category1']); + render(); + apiRef.current.addRowGroupingCriteria('category2', 0); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category2', 'category1']); }); }); - describe('apiRef: removeGroupingCriteria', () => { + describe('apiRef: removeRowGroupingCriteria', () => { it('should remove field from model', () => { - render(); - apiRef.current.removeGroupingCriteria('category1'); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal([]); + render(); + apiRef.current.removeRowGroupingCriteria('category1'); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal([]); }); }); - describe('apiRef: setGroupingCriteriaIndex', () => { + describe('apiRef: setRowGroupingCriteriaIndex', () => { it('should change the grouping criteria order', () => { - render(); - apiRef.current.setGroupingCriteriaIndex('category1', 1); - expect(apiRef.current.state.groupingColumns.model).to.deep.equal(['category2', 'category1']); + render(); + apiRef.current.setRowGroupingCriteriaIndex('category1', 1); + expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category2', 'category1']); }); }); }); diff --git a/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx b/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx index f6496476ef669..f2d084e937292 100644 --- a/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx +++ b/packages/grid/x-data-grid-pro/src/useDataGridProComponent.tsx @@ -27,13 +27,13 @@ import { useGridScroll } from '../../_modules_/grid/hooks/features/scroll/useGri import { useGridEvents } from '../../_modules_/grid/hooks/features/events/useGridEvents'; import { useGridDimensions } from '../../_modules_/grid/hooks/features/dimensions/useGridDimensions'; import { useGridTreeData } from '../../_modules_/grid/hooks/features/treeData/useGridTreeData'; -import { useGridGroupingColumns } from '../../_modules_/grid/hooks/features/groupingColumns/useGridGroupingColumns'; +import { useGridRowGrouping } from '../../_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping'; import { useGridColumnPinning } from '../../_modules_/grid/hooks/features/columnPinning/useGridColumnPinning'; export const useDataGridProComponent = (apiRef: GridApiRef, props: GridComponentProps) => { useGridInitialization(apiRef, props); useGridTreeData(apiRef, props); - useGridGroupingColumns(apiRef, props); + useGridRowGrouping(apiRef, props); useGridSelection(apiRef, props); useGridColumns(apiRef, props); useGridRows(apiRef, props); diff --git a/packages/grid/x-data-grid/src/DataGridProps.ts b/packages/grid/x-data-grid/src/DataGridProps.ts index 8a25b4095c657..6baaf9dc4cddf 100644 --- a/packages/grid/x-data-grid/src/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/DataGridProps.ts @@ -17,7 +17,7 @@ export type DataGridProps = Omit< | 'disableChildrenFiltering' | 'disableChildrenSorting' | 'disableColumnPinning' - | 'disableGroupingColumns' + | 'disableRowGrouping' | 'throttleRowsMs' | 'hideFooterRowCount' | 'options' @@ -29,9 +29,9 @@ export type DataGridProps = Omit< | 'getTreeDataPath' | 'groupingColDef' | 'defaultGroupingExpansionDepth' - | 'groupingColumnMode' - | 'groupingColumnsModel' - | 'onGroupingColumnsModelChange' + | 'rowGroupingColumnMode' + | 'rowGroupingModel' + | 'onRowGroupingModelChange' | 'signature' // TODO: Remove if we have an experimental feature concerning the DataGrid and override the property to only expose the experimental features of the DataGrid. | 'experimentalFeatures' diff --git a/packages/grid/x-data-grid/src/useDataGridProps.ts b/packages/grid/x-data-grid/src/useDataGridProps.ts index 3cd9d1d594af6..8369900acfcbe 100644 --- a/packages/grid/x-data-grid/src/useDataGridProps.ts +++ b/packages/grid/x-data-grid/src/useDataGridProps.ts @@ -19,7 +19,7 @@ const FORCED_PROPS: { [key in ForcedPropsKey]-?: GridInputComponentProps[key] } disableChildrenFiltering: undefined, disableChildrenSorting: undefined, disableColumnPinning: undefined, - disableGroupingColumns: undefined, + disableRowGrouping: undefined, getTreeDataPath: undefined, groupingColDef: undefined, throttleRowsMs: undefined, @@ -32,9 +32,9 @@ const FORCED_PROPS: { [key in ForcedPropsKey]-?: GridInputComponentProps[key] } onPinnedColumnsChange: undefined, defaultGroupingExpansionDepth: undefined, treeData: undefined, - groupingColumnMode: undefined, - groupingColumnsModel: undefined, - onGroupingColumnsModelChange: undefined, + rowGroupingColumnMode: undefined, + rowGroupingModel: undefined, + onRowGroupingModelChange: undefined, experimentalFeatures: undefined, signature: 'DataGrid', }; diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 8ddee1af0654e..54919b72dd08b 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -203,13 +203,6 @@ { "name": "GridFooterPlaceholder", "kind": "Function" }, { "name": "GridGroupingColDefOverride", "kind": "Interface" }, { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, - { "name": "GridGroupingColumnsApi", "kind": "Interface" }, - { "name": "GridGroupingColumnsInitialState", "kind": "Interface" }, - { "name": "GridGroupingColumnsModel", "kind": "TypeAlias" }, - { "name": "gridGroupingColumnsModelSelector", "kind": "Variable" }, - { "name": "gridGroupingColumnsSanitizedModelSelector", "kind": "Variable" }, - { "name": "GridGroupingColumnsState", "kind": "Interface" }, - { "name": "gridGroupingColumnsStateSelector", "kind": "Variable" }, { "name": "GridHeader", "kind": "Variable" }, { "name": "GridHeaderCheckbox", "kind": "ExportSpecifier" }, { "name": "GridHeaderPlaceholder", "kind": "Function" }, @@ -281,7 +274,14 @@ { "name": "GridRowData", "kind": "TypeAlias" }, { "name": "GridRowEntry", "kind": "TypeAlias" }, { "name": "GridRowEventLookup", "kind": "Interface" }, + { "name": "GridRowGroupingApi", "kind": "Interface" }, + { "name": "GridRowGroupingInitialState", "kind": "Interface" }, + { "name": "GridRowGroupingModel", "kind": "TypeAlias" }, + { "name": "gridRowGroupingModelSelector", "kind": "Variable" }, { "name": "gridRowGroupingNameSelector", "kind": "Variable" }, + { "name": "gridRowGroupingSanitizedModelSelector", "kind": "Variable" }, + { "name": "GridRowGroupingState", "kind": "Interface" }, + { "name": "gridRowGroupingStateSelector", "kind": "Variable" }, { "name": "GridRowId", "kind": "TypeAlias" }, { "name": "GridRowIdGetter", "kind": "TypeAlias" }, { "name": "gridRowIdsSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 8ae56838ea731..813082769951a 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -203,13 +203,6 @@ { "name": "GridFooterPlaceholder", "kind": "Function" }, { "name": "GridGroupingColDefOverride", "kind": "Interface" }, { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, - { "name": "GridGroupingColumnsApi", "kind": "Interface" }, - { "name": "GridGroupingColumnsInitialState", "kind": "Interface" }, - { "name": "GridGroupingColumnsModel", "kind": "TypeAlias" }, - { "name": "gridGroupingColumnsModelSelector", "kind": "Variable" }, - { "name": "gridGroupingColumnsSanitizedModelSelector", "kind": "Variable" }, - { "name": "GridGroupingColumnsState", "kind": "Interface" }, - { "name": "gridGroupingColumnsStateSelector", "kind": "Variable" }, { "name": "GridHeader", "kind": "Variable" }, { "name": "GridHeaderCheckbox", "kind": "ExportSpecifier" }, { "name": "GridHeaderPlaceholder", "kind": "Function" }, @@ -281,7 +274,14 @@ { "name": "GridRowData", "kind": "TypeAlias" }, { "name": "GridRowEntry", "kind": "TypeAlias" }, { "name": "GridRowEventLookup", "kind": "Interface" }, + { "name": "GridRowGroupingApi", "kind": "Interface" }, + { "name": "GridRowGroupingInitialState", "kind": "Interface" }, + { "name": "GridRowGroupingModel", "kind": "TypeAlias" }, + { "name": "gridRowGroupingModelSelector", "kind": "Variable" }, { "name": "gridRowGroupingNameSelector", "kind": "Variable" }, + { "name": "gridRowGroupingSanitizedModelSelector", "kind": "Variable" }, + { "name": "GridRowGroupingState", "kind": "Interface" }, + { "name": "gridRowGroupingStateSelector", "kind": "Variable" }, { "name": "GridRowId", "kind": "TypeAlias" }, { "name": "GridRowIdGetter", "kind": "TypeAlias" }, { "name": "gridRowIdsSelector", "kind": "Variable" }, From 4b52f7977b62d2ca5a99a059c63cd01223440f4c Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 16 Dec 2021 09:07:27 +0100 Subject: [PATCH 04/33] Code review: remove 'grouping columns' last occurences --- .../data-grid/group-pivot/group-pivot.md | 18 +++++++++--------- .../components/data-grid/overview/overview.md | 2 +- .../api-docs/data-grid/data-grid-pro-pt.json | 6 +++--- .../api-docs/data-grid/data-grid-pro-zh.json | 6 +++--- .../api-docs/data-grid/data-grid-pro.json | 6 +++--- .../grid/_modules_/grid/GridComponentProps.ts | 4 ++-- .../grid/_modules_/grid/models/gridOptions.tsx | 2 +- .../grid/x-data-grid-pro/src/DataGridPro.tsx | 6 +++--- .../src/tests/rowGrouping.DataGridPro.test.tsx | 4 ++-- 9 files changed, 27 insertions(+), 27 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 7cc44e08039ed..99cd0b6b9311c 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -8,7 +8,7 @@ title: Data Grid - Group & Pivot ## Row grouping [](https://mui.com/store/items/material-ui-pro/) -Use grouping columns to group the rows according to one or several columns value

+Use row grouping to group the rows according to one or several columns value

> ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. > @@ -20,11 +20,11 @@ Use grouping columns to group the rows according to one or several columns value > > The feature is stable in its current form, and we encourage users willing to migrate to the Premium plan once available to start using it. -### Grouping columns definition +### Row grouping definition -#### Initializing the grouping columns +#### Initialize the row grouping -To initialize the grouping columns without controlling them, provide the model to the `initialState` prop: +To initialize the row grouping without controlling it, provide the model to the `initialState` prop: ```ts initialState={{ @@ -36,9 +36,9 @@ initialState={{ {{"demo": "pages/components/data-grid/group-pivot/RowGroupingInitialState.js", "bg": "inline", "defaultCodeOpen": false}} -#### Controlling the grouping columns +#### Control the row grouping -To fully control the grouping columns, provide the model to the `rowGroupingModel` prop. +To fully control the row grouping, provide the model to the `rowGroupingModel` prop. Use it together with `onRowGroupingModelChange` to know when a grouping criteria is added or removed. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingControlled.js", "bg": "inline", "defaultCodeOpen": false}} @@ -49,7 +49,7 @@ Use it together with `onRowGroupingModelChange` to know when a grouping criteria To fully disable the grouping feature, set the `disableRowGrouping` prop to `true`. -It will disable all the features related to the grouping columns, even if a model is provided. +It will disable all the features related to the row grouping, even if a model is provided. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingDisabled.js", "bg": "inline", "defaultCodeOpen": false}} @@ -229,11 +229,11 @@ const rows: GridRowsProp = [ ### Custom grouping column -Same behavior as for the [Grouping Columns](##grouping-column-customization) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. +Same behavior as for the [Row grouping](##grouping-column-customization) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. ### Group expansion -Same behavior as for the [Grouping Columns](#group-expansion) +Same behavior as for the [Row grouping](#group-expansion) ### Gaps in the tree diff --git a/docs/src/pages/components/data-grid/overview/overview.md b/docs/src/pages/components/data-grid/overview/overview.md index 71b8f6336f369..ed9465009cb95 100644 --- a/docs/src/pages/components/data-grid/overview/overview.md +++ b/docs/src/pages/components/data-grid/overview/overview.md @@ -77,8 +77,8 @@ We provide three options: - [Sorting](/components/data-grid/sorting) and [multi-sort](/components/data-grid/sorting/#multi-column-sorting) - [Selection](/components/data-grid/selection/) - [Column virtualization](/components/data-grid/virtualization/#column-virtualization) and [rows virtualization](/components/data-grid/virtualization/#row-virtualization) +- [Row grouping](/components/data-grid/group-pivot/#row-grouping) - [Tree data](/components/data-grid/group-pivot/#tree-data) -- [Grouping columns](/components/data-grid/grouping-columns) - [Resizable columns](/components/data-grid/columns/#column-resizing) - [100% customizable](/components/data-grid/style/) - Server-side data diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index 2adaa71d82262..0d9c898eb8cc8 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -30,7 +30,7 @@ "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", - "disableRowGrouping": "If true, the grouping columns are disabled.", + "disableRowGrouping": "If true, the row grouping is disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -87,7 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", - "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", + "onRowGroupingModelChange": "Callback fired when the row grouping model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -100,7 +100,7 @@ "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "rowGroupingModel": "Set the grouping columns of the grid.", + "rowGroupingModel": "Set the row grouping model of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index 2adaa71d82262..0d9c898eb8cc8 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -30,7 +30,7 @@ "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", - "disableRowGrouping": "If true, the grouping columns are disabled.", + "disableRowGrouping": "If true, the row grouping is disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -87,7 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", - "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", + "onRowGroupingModelChange": "Callback fired when the row grouping model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -100,7 +100,7 @@ "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "rowGroupingModel": "Set the grouping columns of the grid.", + "rowGroupingModel": "Set the row grouping model of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index 2adaa71d82262..0d9c898eb8cc8 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -30,7 +30,7 @@ "disableMultipleColumnsFiltering": "If true, filtering with multiple columns is disabled.", "disableMultipleColumnsSorting": "If true, sorting with multiple columns is disabled.", "disableMultipleSelection": "If true, multiple selection using the CTRL or CMD key is disabled.", - "disableRowGrouping": "If true, the grouping columns are disabled.", + "disableRowGrouping": "If true, the row grouping is disabled.", "disableSelectionOnClick": "If true, the selection on click on a row or cell is disabled.", "disableVirtualization": "If true, the virtualization is disabled.", "editMode": "Controls whether to use the cell or row editing.", @@ -87,7 +87,7 @@ "onRowEditCommit": "Callback fired when the row changes are committed.

Signature:
function(id: GridRowId, event: MuiEvent<MuiBaseEvent>) => void
id: The row id.
event: The event that caused this prop to be called.", "onRowEditStart": "Callback fired when the row turns to edit mode.

Signature:
function(params: GridRowParams, event: MuiEvent<React.KeyboardEvent | React.MouseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", "onRowEditStop": "Callback fired when the row turns to view mode.

Signature:
function(params: GridRowParams, event: MuiEvent<MuiBaseEvent>) => void
params: With all properties from GridRowParams.
event: The event that caused this prop to be called.", - "onRowGroupingModelChange": "Callback fired when the grouping columns model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", + "onRowGroupingModelChange": "Callback fired when the row grouping model changes.

Signature:
function(model: GridRowGroupingModel, details: GridCallbackDetails) => void
model: Columns used as grouping criteria.
details: Additional details for this callback.", "onRowsScrollEnd": "Callback fired when scrolling to the bottom of the grid viewport.

Signature:
function(params: GridRowScrollEndParams, event: MuiEvent<{}>, details: GridCallbackDetails) => void
params: With all properties from GridRowScrollEndParams.
event: The event object.
details: Additional details for this callback.", "onSelectionModelChange": "Callback fired when the selection state of one or multiple rows changes.

Signature:
function(selectionModel: GridSelectionModel, details: GridCallbackDetails) => void
selectionModel: With all the row ids GridSelectionModel.
details: Additional details for this callback.", "onSortModelChange": "Callback fired when the sort model changes before a column is sorted.

Signature:
function(model: GridSortModel, details: GridCallbackDetails) => void
model: With all properties from GridSortModel.
details: Additional details for this callback.", @@ -100,7 +100,7 @@ "rowBuffer": "Number of extra rows to be rendered before/after the visible slice.", "rowCount": "Set the total number of rows, if it is different than the length of the value rows prop. If some of the rows have children (for instance in the tree data), this number represents the amount of top level rows.", "rowGroupingColumnMode": "If single, all column we are grouping by will be represented in the same grouping the same column. If multiple, each column we are grouping by will be represented in its own column.", - "rowGroupingModel": "Set the grouping columns of the grid.", + "rowGroupingModel": "Set the row grouping model of the grid.", "rowHeight": "Set the height in pixel of a row in the grid.", "rows": "Set of rows of type GridRowsProp.", "rowsPerPageOptions": "Select the pageSize dynamically using the component UI.", diff --git a/packages/grid/_modules_/grid/GridComponentProps.ts b/packages/grid/_modules_/grid/GridComponentProps.ts index af066dde568e8..5a8cddef00d02 100644 --- a/packages/grid/_modules_/grid/GridComponentProps.ts +++ b/packages/grid/_modules_/grid/GridComponentProps.ts @@ -364,11 +364,11 @@ interface GridComponentOtherProps extends CommonProps { */ onSortModelChange?: (model: GridSortModel, details: GridCallbackDetails) => void; /** - * Set the grouping columns of the grid. + * Set the row grouping model of the grid. */ rowGroupingModel?: GridRowGroupingModel; /** - * Callback fired when the grouping columns model changes. + * Callback fired when the row grouping model changes. * @param {GridRowGroupingModel} model Columns used as grouping criteria. * @param {GridCallbackDetails} details Additional details for this callback. */ diff --git a/packages/grid/_modules_/grid/models/gridOptions.tsx b/packages/grid/_modules_/grid/models/gridOptions.tsx index 61abe6ed65e26..c91666b42fb4c 100644 --- a/packages/grid/_modules_/grid/models/gridOptions.tsx +++ b/packages/grid/_modules_/grid/models/gridOptions.tsx @@ -162,7 +162,7 @@ export interface GridSimpleOptions { */ disableColumnPinning: boolean; /** - * If `true`, the grouping columns are disabled. + * If `true`, the row grouping is disabled. * @default false */ disableRowGrouping: boolean; diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx index c0efb624a471d..3bdd423a89712 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro.tsx @@ -212,7 +212,7 @@ DataGridProRaw.propTypes = { */ disableMultipleSelection: PropTypes.bool, /** - * If `true`, the grouping columns are disabled. + * If `true`, the row grouping is disabled. * @default false */ disableRowGrouping: PropTypes.bool, @@ -582,7 +582,7 @@ DataGridProRaw.propTypes = { */ onRowEditStop: PropTypes.func, /** - * Callback fired when the grouping columns model changes. + * Callback fired when the row grouping model changes. * @param {GridRowGroupingModel} model Columns used as grouping criteria. * @param {GridCallbackDetails} details Additional details for this callback. */ @@ -661,7 +661,7 @@ DataGridProRaw.propTypes = { */ rowGroupingColumnMode: PropTypes.oneOf(['multiple', 'single']), /** - * Set the grouping columns of the grid. + * Set the row grouping model of the grid. */ rowGroupingModel: PropTypes.arrayOf(PropTypes.string), /** diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index 6149892c696c1..40ded8f5d5af0 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -71,7 +71,7 @@ describe(' - Group Rows By Column', () => { describe('Setting grouping criteria', () => { describe('initialState: rowGrouping.model', () => { - it('should allow to initialize the grouping columns', () => { + it('should allow to initialize the row grouping', () => { render( - Group Rows By Column', () => { expect(disableRowGroupingSpy.lastCall.firstArg).to.equal(true); }); - it('should disable grouping columns when `prop.disableRowGrouping = true`', () => { + it('should disable the row grouping when `prop.disableRowGrouping = true`', () => { render( Date: Thu, 16 Dec 2021 09:12:15 +0100 Subject: [PATCH 05/33] Work --- .../data-grid/group-pivot/group-pivot.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 99cd0b6b9311c..410d15a412515 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -20,7 +20,7 @@ Use row grouping to group the rows according to one or several columns value

> > The feature is stable in its current form, and we encourage users willing to migrate to the Premium plan once available to start using it. -### Row grouping definition +### Set grouping criteria #### Initialize the row grouping @@ -36,16 +36,16 @@ initialState={{ {{"demo": "pages/components/data-grid/group-pivot/RowGroupingInitialState.js", "bg": "inline", "defaultCodeOpen": false}} -#### Control the row grouping +#### Controlled row grouping -To fully control the row grouping, provide the model to the `rowGroupingModel` prop. -Use it together with `onRowGroupingModelChange` to know when a grouping criteria is added or removed. +Use the `rowGroupingModel` prop to control the criteria used to group the rows. +You can use the `onRowGroupingModelChange` prop to listen to changes to the page size and update the prop accordingly. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingControlled.js", "bg": "inline", "defaultCodeOpen": false}} -### Disable the grouping +### Disable the row grouping -#### Fully disable the grouping +#### For all columns To fully disable the grouping feature, set the `disableRowGrouping` prop to `true`. @@ -53,13 +53,15 @@ It will disable all the features related to the row grouping, even if a model is {{"demo": "pages/components/data-grid/group-pivot/RowGroupingDisabled.js", "bg": "inline", "defaultCodeOpen": false}} -#### Disable the grouping for some columns +#### For some columns To block the grouping of certain columns, set the `canBeGrouped` property of `GridColDef` to `false`. In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} +### Grouping columns + #### Single grouping column By default, the grid will create only one grouping column even if you have several grouping criteria. @@ -72,7 +74,7 @@ To have a grouping column for each grouping criteria, set the `rowGroupingColumn {{"demo": "pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} -### Custom grouping column +#### Custom grouping column Use the `groupingColDef` prop to customize the rendering of the grouping column. You can override any property of the `GridColDef` interface except the `field`, the `type` and the properties related to the edition. From f64cf411cc29f56abab8841f0d9cbd8fa9e3e03d Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 20 Dec 2021 09:21:42 +0100 Subject: [PATCH 06/33] Code review: grouapable + default doc --- docs/pages/api-docs/data-grid/data-grid-pro.json | 14 ++++++++++---- docs/pages/api-docs/data-grid/data-grid.json | 14 ++++++++++---- docs/pages/api-docs/data-grid/grid-col-def.md | 2 +- .../group-pivot/RowGroupingColDefCanBeGrouped.js | 2 +- .../group-pivot/RowGroupingColDefCanBeGrouped.tsx | 2 +- .../data-grid/group-pivot/group-pivot.md | 2 +- .../grid/_modules_/grid/components/icons/index.tsx | 4 ++-- .../menu/columnMenu/GridRowGroupingMenuItems.tsx | 2 +- .../features/rowGrouping/createGroupingColDef.tsx | 4 ++-- .../rowGrouping/gridRowGroupingSelector.ts | 2 +- .../features/rowGrouping/useGridRowGrouping.tsx | 5 ++--- .../features/treeData/gridTreeDataGroupColDef.ts | 4 ++-- .../hooks/features/treeData/useGridTreeData.tsx | 2 +- .../grid/hooks/utils/useGridProcessedProps.ts | 10 +++++----- .../_modules_/grid/models/colDef/gridColDef.ts | 4 ++-- .../grid/models/colDef/gridStringColDef.ts | 2 +- .../grid/models/gridIconSlotsComponent.ts | 4 ++++ .../grid/x-data-grid-generator/src/useMovieData.ts | 4 ++-- .../src/tests/rowGrouping.DataGridPro.test.tsx | 10 +++++----- scripts/x-data-grid-pro.exports.json | 2 +- scripts/x-data-grid.exports.json | 2 +- 21 files changed, 56 insertions(+), 41 deletions(-) diff --git a/docs/pages/api-docs/data-grid/data-grid-pro.json b/docs/pages/api-docs/data-grid/data-grid-pro.json index 17fc66a1f81a2..e74c0d667662e 100644 --- a/docs/pages/api-docs/data-grid/data-grid-pro.json +++ b/docs/pages/api-docs/data-grid/data-grid-pro.json @@ -234,8 +234,14 @@ "ExportIcon": { "default": "GridSaveAltIcon", "type": { "name": "elementType" } }, "FilterPanel": { "default": "GridFilterPanel", "type": { "name": "elementType" } }, "Footer": { "default": "GridFooter", "type": { "name": "elementType" } }, - "GroupingCriteriaCollapseIcon": { "type": { "name": "elementType" } }, - "GroupingCriteriaExpandIcon": { "type": { "name": "elementType" } }, + "GroupingCriteriaCollapseIcon": { + "default": "GridExpandMoreIcon", + "type": { "name": "elementType" } + }, + "GroupingCriteriaExpandIcon": { + "default": "KeyboardArrowRight", + "type": { "name": "elementType" } + }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, "LoadingOverlay": { "default": "GridLoadingOverlay", "type": { "name": "elementType" } }, "MoreActionsIcon": { "default": "GridMoreVertIcon", "type": { "name": "elementType" } }, @@ -247,8 +253,8 @@ "PreferencesPanel": { "default": "GridPreferencesPanel", "type": { "name": "elementType" } }, "Row": { "type": { "name": "elementType" } }, "Toolbar": { "default": "null", "type": { "name": "elementType | null" } }, - "TreeDataCollapseIcon": { "type": { "name": "elementType" } }, - "TreeDataExpandIcon": { "type": { "name": "elementType" } } + "TreeDataCollapseIcon": { "default": "GridExpandMoreIcon", "type": { "name": "elementType" } }, + "TreeDataExpandIcon": { "default": "KeyboardArrowRight", "type": { "name": "elementType" } } }, "name": "DataGridPro", "styles": { diff --git a/docs/pages/api-docs/data-grid/data-grid.json b/docs/pages/api-docs/data-grid/data-grid.json index 9bb187985e99e..c315fd662cc55 100644 --- a/docs/pages/api-docs/data-grid/data-grid.json +++ b/docs/pages/api-docs/data-grid/data-grid.json @@ -184,8 +184,14 @@ "ExportIcon": { "default": "GridSaveAltIcon", "type": { "name": "elementType" } }, "FilterPanel": { "default": "GridFilterPanel", "type": { "name": "elementType" } }, "Footer": { "default": "GridFooter", "type": { "name": "elementType" } }, - "GroupingCriteriaCollapseIcon": { "type": { "name": "elementType" } }, - "GroupingCriteriaExpandIcon": { "type": { "name": "elementType" } }, + "GroupingCriteriaCollapseIcon": { + "default": "GridExpandMoreIcon", + "type": { "name": "elementType" } + }, + "GroupingCriteriaExpandIcon": { + "default": "KeyboardArrowRight", + "type": { "name": "elementType" } + }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, "LoadingOverlay": { "default": "GridLoadingOverlay", "type": { "name": "elementType" } }, "MoreActionsIcon": { "default": "GridMoreVertIcon", "type": { "name": "elementType" } }, @@ -197,8 +203,8 @@ "PreferencesPanel": { "default": "GridPreferencesPanel", "type": { "name": "elementType" } }, "Row": { "type": { "name": "elementType" } }, "Toolbar": { "default": "null", "type": { "name": "elementType | null" } }, - "TreeDataCollapseIcon": { "type": { "name": "elementType" } }, - "TreeDataExpandIcon": { "type": { "name": "elementType" } } + "TreeDataCollapseIcon": { "default": "GridExpandMoreIcon", "type": { "name": "elementType" } }, + "TreeDataExpandIcon": { "default": "KeyboardArrowRight", "type": { "name": "elementType" } } }, "name": "DataGrid", "styles": { diff --git a/docs/pages/api-docs/data-grid/grid-col-def.md b/docs/pages/api-docs/data-grid/grid-col-def.md index 7806edb299c0e..0a394a73afce9 100644 --- a/docs/pages/api-docs/data-grid/grid-col-def.md +++ b/docs/pages/api-docs/data-grid/grid-col-def.md @@ -15,7 +15,6 @@ import { GridColDef } from '@mui/x-data-grid'; | Name | Type | Default | Description | | :-------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | align? | GridAlignment | | Allows to align the column values in cells. | -| canBeGrouped? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only). | | cellClassName? | GridCellClassNamePropType | | Class name that will be added in cells for that column. | | description? | string | | The description of the column rendered as tooltip if the column header name is not fully displayed. | | disableColumnMenu? | boolean | false | If `true`, the column menu is disabled for this column. | @@ -26,6 +25,7 @@ import { GridColDef } from '@mui/x-data-grid'; | filterable? | boolean | true | If `true`, the column is filterable. | | filterOperators? | GridFilterOperator[] | | Allows setting the filter operators for this column. | | flex? | number | | If set, it indicates that a column has fluid width. Range [0, ∞). | +| groupable? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only). | | headerAlign? | GridAlignment | | Header cell element alignment. | | headerClassName? | GridColumnHeaderClassNamePropType | | Class name that will be added in the column header cell. | | headerName? | string | | The title of the column rendered in the column header cell. | diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js index b1742b02655ea..6d7be1765826e 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js @@ -47,7 +47,7 @@ export default function RowGroupingColDefCanBeGrouped() { const columnWithNoDirectorGroup = React.useMemo( () => columns.map((colDef) => - colDef.field === 'director' ? { ...colDef, canBeGrouped: false } : colDef, + colDef.field === 'director' ? { ...colDef, groupable: false } : colDef, ), [columns], ); diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx index 721f2759b6512..69e627e9f6f48 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.tsx @@ -58,7 +58,7 @@ export default function RowGroupingColDefCanBeGrouped() { const columnWithNoDirectorGroup = React.useMemo( () => columns.map((colDef) => - colDef.field === 'director' ? { ...colDef, canBeGrouped: false } : colDef, + colDef.field === 'director' ? { ...colDef, groupable: false } : colDef, ), [columns], ); diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 410d15a412515..d304c38fe0205 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -55,7 +55,7 @@ It will disable all the features related to the row grouping, even if a model is #### For some columns -To block the grouping of certain columns, set the `canBeGrouped` property of `GridColDef` to `false`. +To block the grouping of certain columns, set the `groupable` property of `GridColDef` to `false`. In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} diff --git a/packages/grid/_modules_/grid/components/icons/index.tsx b/packages/grid/_modules_/grid/components/icons/index.tsx index 4e4a83b7542b4..5bbef3accbfcb 100644 --- a/packages/grid/_modules_/grid/components/icons/index.tsx +++ b/packages/grid/_modules_/grid/components/icons/index.tsx @@ -11,12 +11,12 @@ export const GridArrowDownwardIcon = createSvgIcon( 'ArrowDownward', ); -export const GridExpandMoreIcon = createSvgIcon( +export const KeyboardArrowRight = createSvgIcon( , 'KeyboardArrowRight', ); -export const GridExpandLessIcon = createSvgIcon( +export const GridExpandMoreIcon = createSvgIcon( , 'ExpandMore', ); diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx index 3235c7a0d14b6..8f60f6ef79ef9 100644 --- a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx @@ -92,7 +92,7 @@ const GridRowGroupingMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { ); } - if (!column.canBeGrouped) { + if (!column.groupable) { return null; } diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx index bcbc5d0e38d7c..30d5245a5c13c 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -20,10 +20,10 @@ const GROUPING_COL_DEF_DEFAULT_PROPERTIES: Omit = { disableReorder: true, }; -const GROUPING_COL_DEF_FORCED_PROPERTIES: Pick = { +const GROUPING_COL_DEF_FORCED_PROPERTIES: Pick = { type: 'rowGroupByColumnsGroup', editable: false, - canBeGrouped: false, + groupable: false, }; /** diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts index dbd486fbb9ef2..72558ef4bc08d 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingSelector.ts @@ -13,5 +13,5 @@ export const gridRowGroupingSanitizedModelSelector = createSelector( gridRowGroupingModelSelector, gridColumnLookupSelector, (model, columnsLookup) => - model.filter((field) => !!columnsLookup[field] && columnsLookup[field].canBeGrouped), + model.filter((field) => !!columnsLookup[field] && columnsLookup[field].groupable), ); diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 34179e59fa697..eb476ae004e23 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -205,10 +205,10 @@ export const useGridRowGrouping = ( React.useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; - return; + return () => {}; } - updateRowGrouping(); + return updateRowGrouping(); }, [updateRowGrouping]); /** @@ -325,7 +325,6 @@ export const useGridRowGrouping = ( rowTree, rowIds, sortRowList: params.sortRowList, - comparatorList: params.comparatorList, disableChildrenSorting: false, }); }, diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts index a24946bc9b531..07b53cd6bdf6b 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts +++ b/packages/grid/_modules_/grid/hooks/features/treeData/gridTreeDataGroupColDef.ts @@ -19,9 +19,9 @@ export const GRID_TREE_DATA_GROUP_COL_DEF: Omit = { field: '__tree_data_group__', editable: false, - canBeGrouped: false, + groupable: false, }; diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx index 81e6a5a9681c1..0b02515581c8f 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx +++ b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx @@ -91,7 +91,7 @@ export const useGridTreeData = ( return; } - updateRowGrouping(); + return updateRowGrouping(); }, [updateRowGrouping]); /** diff --git a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts index 951a0f2792b72..6fb6da9178225 100644 --- a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts +++ b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts @@ -32,7 +32,7 @@ import { GridViewStreamIcon, GridMoreVertIcon, GridExpandMoreIcon, - GridExpandLessIcon, + KeyboardArrowRight, } from '../../components'; import { GridColumnUnsortedIcon } from '../../components/columnHeaders/GridColumnUnsortedIcon'; import { ErrorOverlay } from '../../components/ErrorOverlay'; @@ -54,10 +54,10 @@ const DEFAULT_GRID_ICON_SLOTS_COMPONENTS: GridIconSlotsComponent = { DensityComfortableIcon: GridViewStreamIcon, ExportIcon: GridSaveAltIcon, MoreActionsIcon: GridMoreVertIcon, - TreeDataCollapseIcon: GridExpandLessIcon, - TreeDataExpandIcon: GridExpandMoreIcon, - GroupingCriteriaCollapseIcon: GridExpandLessIcon, - GroupingCriteriaExpandIcon: GridExpandMoreIcon, + TreeDataCollapseIcon: GridExpandMoreIcon, + TreeDataExpandIcon: KeyboardArrowRight, + GroupingCriteriaCollapseIcon: GridExpandMoreIcon, + GroupingCriteriaExpandIcon: KeyboardArrowRight, }; const DEFAULT_GRID_SLOTS_COMPONENTS: GridSlotsComponent = { diff --git a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts index 0ad3910165098..3a3526ba1f74b 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts @@ -88,7 +88,7 @@ export interface GridColDef { * If `true`, the rows can be grouped based on this column values (pro-plan only). * @default true */ - canBeGrouped?: boolean; + groupable?: boolean; /** * If `false`, the menu items for column pinning menu will not be rendered. * Only available in DataGridPro. @@ -253,7 +253,7 @@ export interface GridGroupingColDefOverride | 'type' | 'preProcessEditCellProps' | 'renderEditCell' - | 'canBeGrouped' + | 'groupable' > { /** * The field from which we want to apply the sorting and the filtering for the grouping column. diff --git a/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts index 09b6c0f73202e..b7dcbc1a1b098 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridStringColDef.ts @@ -10,7 +10,7 @@ export const GRID_STRING_COL_DEF: GridColTypeDef = { sortable: true, resizable: true, filterable: true, - canBeGrouped: true, + groupable: true, pinnable: true, editable: false, sortComparator: gridStringNumberComparer, diff --git a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts index 30e2a3556309f..e84391c95dbdf 100644 --- a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts +++ b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts @@ -81,18 +81,22 @@ export interface GridIconSlotsComponent { MoreActionsIcon: React.JSXElementConstructor; /** * Icon displayed on the tree data toggling column when the children are collapsed + * @default KeyboardArrowRight */ TreeDataExpandIcon: React.JSXElementConstructor; /** * Icon displayed on the tree data toggling column when the children are expanded + * @default GridExpandMoreIcon */ TreeDataCollapseIcon: React.JSXElementConstructor; /** * Icon displayed on the grouping column when the children are collapsed + * @default KeyboardArrowRight */ GroupingCriteriaExpandIcon: React.JSXElementConstructor; /** * Icon displayed on the grouping column when the children are expanded + * @default GridExpandMoreIcon */ GroupingCriteriaCollapseIcon: React.JSXElementConstructor; } diff --git a/packages/grid/x-data-grid-generator/src/useMovieData.ts b/packages/grid/x-data-grid-generator/src/useMovieData.ts index 4a032f9bd7f92..1424f2c4e9855 100644 --- a/packages/grid/x-data-grid-generator/src/useMovieData.ts +++ b/packages/grid/x-data-grid-generator/src/useMovieData.ts @@ -11,13 +11,13 @@ type Movie = { }; const COLUMNS: GridColumns = [ - { field: 'title', headerName: 'Title', width: 200, canBeGrouped: false }, + { field: 'title', headerName: 'Title', width: 200, groupable: false }, { field: 'gross', headerName: 'Gross', type: 'number', width: 150, - canBeGrouped: false, + groupable: false, valueFormatter: ({ value }) => { if (!value || typeof value !== 'number') { return value; diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index 40ded8f5d5af0..f5e1534feeeb8 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -146,7 +146,7 @@ describe(' - Group Rows By Column', () => { expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); }); - it('should ignore grouping criteria with colDef.canBeGrouped = false', () => { + it('should ignore grouping criteria with colDef.groupable = false', () => { render( - Group Rows By Column', () => { }, { field: 'category2', - canBeGrouped: false, + groupable: false, }, ]} initialState={{ rowGrouping: { model: ['category1', 'category2'] } }} @@ -1283,7 +1283,7 @@ describe(' - Group Rows By Column', () => { }); describe('column menu', () => { - it('should add a "Group by {field}" menu item on ungrouped columns when coLDef.canBeGrouped is not defined', () => { + it('should add a "Group by {field}" menu item on ungrouped columns when coLDef.groupable is not defined', () => { render( - Group Rows By Column', () => { expect(apiRef.current.state.rowGrouping.model).to.deep.equal(['category1']); }); - it('should not add a "Group by {field}" menu item on ungrouped columns when coLDef.canBeGrouped = false', () => { + it('should not add a "Group by {field}" menu item on ungrouped columns when coLDef.groupable = false', () => { render( - Group Rows By Column', () => { }, { field: 'category1', - canBeGrouped: false, + groupable: false, }, ]} />, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 89d8571a2c95f..24e764c0eaf77 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -162,7 +162,6 @@ { "name": "GridEventPublisher", "kind": "TypeAlias" }, { "name": "GridEvents", "kind": "Enum" }, { "name": "GridEventsStr", "kind": "TypeAlias" }, - { "name": "GridExpandLessIcon", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExportFormat", "kind": "TypeAlias" }, { "name": "GridExportOptions", "kind": "Interface" }, @@ -374,6 +373,7 @@ { "name": "HideGridColMenuItem", "kind": "ExportSpecifier" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, + { "name": "KeyboardArrowRight", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, { "name": "LicenseInfo", "kind": "ExportSpecifier" }, { "name": "Logger", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 8527b1c418120..531e857fc04e2 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -162,7 +162,6 @@ { "name": "GridEventPublisher", "kind": "TypeAlias" }, { "name": "GridEvents", "kind": "Enum" }, { "name": "GridEventsStr", "kind": "TypeAlias" }, - { "name": "GridExpandLessIcon", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExportFormat", "kind": "TypeAlias" }, { "name": "GridExportOptions", "kind": "Interface" }, @@ -374,6 +373,7 @@ { "name": "HideGridColMenuItem", "kind": "ExportSpecifier" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, + { "name": "KeyboardArrowRight", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, { "name": "Logger", "kind": "Interface" }, { "name": "MAX_PAGE_SIZE", "kind": "Variable" }, From 4127ec58a12db7aa3a03f0b1da08bd2e925b81ab Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 21 Dec 2021 11:12:33 +0100 Subject: [PATCH 07/33] Work --- .../_modules_/grid/hooks/features/treeData/useGridTreeData.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx index 0b02515581c8f..81e6a5a9681c1 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx +++ b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx @@ -91,7 +91,7 @@ export const useGridTreeData = ( return; } - return updateRowGrouping(); + updateRowGrouping(); }, [updateRowGrouping]); /** From 25fe3937219f41835103683e15879c306a2a2b23 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 21 Dec 2021 11:59:34 +0100 Subject: [PATCH 08/33] Fix --- ...oupingIsGroupExpandedByDefault.tsx.preview | 26 +++++++++---------- .../rowGrouping/useGridRowGrouping.tsx | 7 ++++- .../grid/utils/tree/buildRowTree.test.ts | 6 +++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingIsGroupExpandedByDefault.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingIsGroupExpandedByDefault.tsx.preview index fd87d89bb424e..6ae78aa78205d 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingIsGroupExpandedByDefault.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingIsGroupExpandedByDefault.tsx.preview @@ -1,15 +1,15 @@ \ No newline at end of file diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index eade2fd642681..1637e6cce546a 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -197,7 +197,12 @@ export const useGridRowGrouping = ( }; return apiRef.current.unstable_registerRowGroupsBuilder('rowGrouping', groupRows); - }, [apiRef, props.defaultGroupingExpansionDepth, props.disableRowGrouping]); + }, [ + apiRef, + props.defaultGroupingExpansionDepth, + props.isGroupExpandedByDefault, + props.disableRowGrouping, + ]); useFirstRender(() => { updateRowGrouping(); diff --git a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts index 75922e13dbbb1..b281258931b9b 100644 --- a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts +++ b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts @@ -313,7 +313,8 @@ describe('buildRowTree', () => { expect(response.tree).to.deep.equal({ '0': { id: 0, - childrenExpanded: true, + childrenExpanded: false, + isAutoGenerated: false, parent: 'auto-generated-row-field1/value-1-1-field2/value-2-1', groupingKey: 'value-leaf-1', groupingField: null, @@ -322,7 +323,8 @@ describe('buildRowTree', () => { }, '1': { id: 1, - childrenExpanded: true, + childrenExpanded: false, + isAutoGenerated: false, parent: 'auto-generated-row-field2/value-2-1', groupingKey: 'value-leaf-1', groupingField: null, From 258b3c160f749ea3977bc07781473e9fc43daad3 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Fri, 24 Dec 2021 20:39:15 -0300 Subject: [PATCH 09/33] Translations for ptBR --- packages/grid/_modules_/grid/locales/ptBR.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grid/_modules_/grid/locales/ptBR.ts b/packages/grid/_modules_/grid/locales/ptBR.ts index 7f5a88711b6c2..0d9eaef7fc3fb 100644 --- a/packages/grid/_modules_/grid/locales/ptBR.ts +++ b/packages/grid/_modules_/grid/locales/ptBR.ts @@ -118,9 +118,9 @@ const ptBRGrid: Partial = { // treeDataCollapse: 'hide children', // Grouping columns - // groupingColumnHeaderName: 'Group', - // groupColumn: name => `Group by ${name}`, - // unGroupColumn: name => `Stop grouping by ${name}`, + groupingColumnHeaderName: 'Grupo', + groupColumn: name => `Agrupar por ${name}`, + unGroupColumn: name => `Parar agrupamento por ${name}`, }; export const ptBR: Localization = getGridLocalization(ptBRGrid, ptBRCore); From c50bd93747c7142d71279756ae068d24004f1085 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Fri, 24 Dec 2021 23:58:28 -0300 Subject: [PATCH 10/33] yarn prettier --- packages/grid/_modules_/grid/locales/ptBR.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grid/_modules_/grid/locales/ptBR.ts b/packages/grid/_modules_/grid/locales/ptBR.ts index 0d9eaef7fc3fb..b78df114ba3af 100644 --- a/packages/grid/_modules_/grid/locales/ptBR.ts +++ b/packages/grid/_modules_/grid/locales/ptBR.ts @@ -119,8 +119,8 @@ const ptBRGrid: Partial = { // Grouping columns groupingColumnHeaderName: 'Grupo', - groupColumn: name => `Agrupar por ${name}`, - unGroupColumn: name => `Parar agrupamento por ${name}`, + groupColumn: (name) => `Agrupar por ${name}`, + unGroupColumn: (name) => `Parar agrupamento por ${name}`, }; export const ptBR: Localization = getGridLocalization(ptBRGrid, ptBRCore); From c670b28233f4f39bd80aaeaea7452ade7fcc91a7 Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 3 Jan 2022 10:16:03 +0100 Subject: [PATCH 11/33] Code review: Matheus --- docs/pages/api-docs/data-grid/grid-api.md | 4 ++-- docs/pages/api-docs/data-grid/grid-row-grouping-api.json | 4 ++-- .../pages/components/data-grid/group-pivot/group-pivot.md | 2 +- packages/grid/_modules_/grid/components/icons/index.tsx | 2 +- .../features/rowGrouping/gridRowGroupingInterfaces.ts | 4 ++-- .../hooks/features/rowGrouping/gridRowGroupingUtils.ts | 8 ++++---- .../hooks/features/rowGrouping/useGridRowGrouping.tsx | 7 ++++--- .../grid/hooks/features/treeData/useGridTreeData.tsx | 8 ++++---- .../_modules_/grid/hooks/utils/useGridProcessedProps.ts | 6 +++--- scripts/x-data-grid-pro.exports.json | 2 +- scripts/x-data-grid.exports.json | 2 +- 11 files changed, 25 insertions(+), 24 deletions(-) diff --git a/docs/pages/api-docs/data-grid/grid-api.md b/docs/pages/api-docs/data-grid/grid-api.md index d5ebf3047a6d3..b99e7207830c8 100644 --- a/docs/pages/api-docs/data-grid/grid-api.md +++ b/docs/pages/api-docs/data-grid/grid-api.md @@ -12,7 +12,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | Name | Type | Description | | :--------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| addRowGroupingCriteria | (groupingCriteriaField: string, groupingIndex?: number) => void | Add the field to the rowGroupingModel. | +| addRowGroupingCriteria | (groupingCriteriaField: string, groupingIndex?: number) => void | Adds the field to the row grouping model. | | applySorting | () => void | Applies the current sort model to the rows. | | commitCellChange | (params: GridCommitCellChangeParams, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the field at the given id with the value stored in the edit row model. | | commitRowChange | (id: GridRowId, event?: MuiBaseEvent) => boolean \| Promise<boolean> | Updates the row at the given id with the values stored in the edit row model. | @@ -61,7 +61,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | isRowSelected | (id: GridRowId) => boolean | Determines if a row is selected or not. | | pinColumn | (field: string, side: GridPinnedPosition) => void | Pins a column to the left or right side of the grid. | | publishEvent | GridEventPublisher | Emits an event. | -| removeRowGroupingCriteria | (groupingCriteriaField: string) => void | Remove the field from to rowGroupingModel. | +| removeRowGroupingCriteria | (groupingCriteriaField: string) => void | sRemove the field from the row grouping model. | | resize | () => void | Triggers a resize of the component and recalculation of width and height. | | scroll | (params: Partial<GridScrollParams>) => void | Triggers the viewport to scroll to the given positions (in pixels). | | scrollToIndexes | (params: Partial<GridCellIndexCoordinates>) => boolean | Triggers the viewport to scroll to the cell at indexes given by `params`.
Returns `true` if the grid had to scroll to reach the target. | diff --git a/docs/pages/api-docs/data-grid/grid-row-grouping-api.json b/docs/pages/api-docs/data-grid/grid-row-grouping-api.json index 463d17158f4ff..7d0865fc802a2 100644 --- a/docs/pages/api-docs/data-grid/grid-row-grouping-api.json +++ b/docs/pages/api-docs/data-grid/grid-row-grouping-api.json @@ -4,12 +4,12 @@ "properties": [ { "name": "addRowGroupingCriteria", - "description": "Add the field to the rowGroupingModel.", + "description": "Adds the field to the row grouping model.", "type": "(groupingCriteriaField: string, groupingIndex?: number) => void" }, { "name": "removeRowGroupingCriteria", - "description": "Remove the field from to rowGroupingModel.", + "description": "sRemove the field from the row grouping model.", "type": "(groupingCriteriaField: string) => void" }, { diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index ef816818e65f9..4a0377decd678 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -142,7 +142,7 @@ When defined, this callback will always have the priority over the `defaultGroup ```tsx isGroupExpandedByDefault={ - node => node.groupingField === 'company' && node.groupingKey === '20th Century Fox' + node => node.groupingField === 'company' && node.groupingKey === '20th Century Fox' } ``` diff --git a/packages/grid/_modules_/grid/components/icons/index.tsx b/packages/grid/_modules_/grid/components/icons/index.tsx index 5bbef3accbfcb..2c117dfb864ef 100644 --- a/packages/grid/_modules_/grid/components/icons/index.tsx +++ b/packages/grid/_modules_/grid/components/icons/index.tsx @@ -11,7 +11,7 @@ export const GridArrowDownwardIcon = createSvgIcon( 'ArrowDownward', ); -export const KeyboardArrowRight = createSvgIcon( +export const GridKeyboardArrowRight = createSvgIcon( , 'KeyboardArrowRight', ); diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts index e121f28fdb0c2..6c2382be9265d 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts @@ -16,14 +16,14 @@ export interface GridRowGroupingApi { setRowGroupingModel: (model: GridRowGroupingModel) => void; /** - * Add the field to the rowGroupingModel. + * Adds the field to the row grouping model. * @param {string} groupingCriteriaField The field from which we want to group the rows. * @param {number | undefined} groupingIndex The grouping index at which we want to insert the new grouping criteria. By default, it will be inserted at the end of the model. */ addRowGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => void; /** - * Remove the field from to rowGroupingModel. + * sRemove the field from the row grouping model. * @param {string} groupingCriteriaField The field from which we want to stop grouping the rows. */ removeRowGroupingCriteria: (groupingCriteriaField: string) => void; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts index ad1a6a13a5e4a..86d19b7299782 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts @@ -133,15 +133,15 @@ export const filterRowTreeFromGroupingColumns = ( }; export const getColDefOverrides = ( - propGroupingColDef: GridComponentProps['groupingColDef'], + groupingColDefProp: GridComponentProps['groupingColDef'], fields: string[], ) => { - if (typeof propGroupingColDef === 'function') { - return propGroupingColDef({ + if (typeof groupingColDefProp === 'function') { + return groupingColDefProp({ groupingName: GROUPING_COLUMNS_FEATURE_NAME, fields, }); } - return propGroupingColDef; + return groupingColDefProp; }; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 1637e6cce546a..84b156333f858 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -227,7 +227,7 @@ export const useGridRowGrouping = ( return []; } - const propGroupingColDef = props.groupingColDef; + const groupingColDefProp = props.groupingColDef; // We can't use `gridGroupingRowsSanitizedModelSelector` here because the new columns are not in the state yet const rowGroupingModel = gridRowGroupingModelSelector(apiRef.current.state).filter( @@ -244,7 +244,7 @@ export const useGridRowGrouping = ( createGroupingColDefForAllGroupingCriteria({ apiRef, rowGroupingModel, - colDefOverride: getColDefOverrides(propGroupingColDef, rowGroupingModel), + colDefOverride: getColDefOverrides(groupingColDefProp, rowGroupingModel), columnsLookup: columnsState.lookup, }), ]; @@ -254,7 +254,7 @@ export const useGridRowGrouping = ( return rowGroupingModel.map((groupingCriteria) => createGroupingColDefForOneGroupingCriteria({ groupingCriteria, - colDefOverride: getColDefOverrides(propGroupingColDef, [groupingCriteria]), + colDefOverride: getColDefOverrides(groupingColDefProp, [groupingCriteria]), groupedByColDef: columnsState.lookup[groupingCriteria], columnsLookup: columnsState.lookup, }), @@ -458,6 +458,7 @@ export const useGridRowGrouping = ( const lastGroupingColumnsModelApplied = sanitizedModelOnLastRowPreProcessing.current; if (!isDeepEqual(lastGroupingColumnsModelApplied, rowGroupingModel)) { + console.log(lastGroupingColumnsModelApplied, rowGroupingModel) sanitizedModelOnLastRowPreProcessing.current = rowGroupingModel; // Refresh the column pre-processing diff --git a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx index ac9f117056f72..5f9b2b53fc9e1 100644 --- a/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx +++ b/packages/grid/_modules_/grid/hooks/features/treeData/useGridTreeData.tsx @@ -106,18 +106,18 @@ export const useGridTreeData = ( * PRE-PROCESSING */ const getGroupingColDef = React.useCallback((): GridColDef => { - const propGroupingColDef = props.groupingColDef; + const groupingColDefProp = props.groupingColDef; let colDefOverride: GridGroupingColDefOverride | null | undefined; - if (typeof propGroupingColDef === 'function') { + if (typeof groupingColDefProp === 'function') { const params: GridGroupingColDefOverrideParams = { groupingName: TREE_DATA_GROUPING_NAME, fields: [], }; - colDefOverride = propGroupingColDef(params); + colDefOverride = groupingColDefProp(params); } else { - colDefOverride = propGroupingColDef; + colDefOverride = groupingColDefProp; } const { hideDescendantCount, ...colDefOverrideProperties } = colDefOverride ?? {}; diff --git a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts index 6fb6da9178225..b35c174ed67fa 100644 --- a/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts +++ b/packages/grid/_modules_/grid/hooks/utils/useGridProcessedProps.ts @@ -32,7 +32,7 @@ import { GridViewStreamIcon, GridMoreVertIcon, GridExpandMoreIcon, - KeyboardArrowRight, + GridKeyboardArrowRight, } from '../../components'; import { GridColumnUnsortedIcon } from '../../components/columnHeaders/GridColumnUnsortedIcon'; import { ErrorOverlay } from '../../components/ErrorOverlay'; @@ -55,9 +55,9 @@ const DEFAULT_GRID_ICON_SLOTS_COMPONENTS: GridIconSlotsComponent = { ExportIcon: GridSaveAltIcon, MoreActionsIcon: GridMoreVertIcon, TreeDataCollapseIcon: GridExpandMoreIcon, - TreeDataExpandIcon: KeyboardArrowRight, + TreeDataExpandIcon: GridKeyboardArrowRight, GroupingCriteriaCollapseIcon: GridExpandMoreIcon, - GroupingCriteriaExpandIcon: KeyboardArrowRight, + GroupingCriteriaExpandIcon: GridKeyboardArrowRight, }; const DEFAULT_GRID_SLOTS_COMPONENTS: GridSlotsComponent = { diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index f33ff16a0a3c5..09c4369ce8cfa 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -212,6 +212,7 @@ { "name": "GridInitialState", "kind": "Interface" }, { "name": "GridInputComponentProps", "kind": "Interface" }, { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, + { "name": "GridKeyboardArrowRight", "kind": "Variable" }, { "name": "GridKeyGetterParams", "kind": "Interface" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, { "name": "GridLinkOperator", "kind": "Enum" }, @@ -374,7 +375,6 @@ { "name": "HideGridColMenuItem", "kind": "ExportSpecifier" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, - { "name": "KeyboardArrowRight", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, { "name": "LicenseInfo", "kind": "ExportSpecifier" }, { "name": "Logger", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 64ccc1ddc61a0..6d2067c00f218 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -212,6 +212,7 @@ { "name": "GridInitialState", "kind": "Interface" }, { "name": "GridInputComponentProps", "kind": "Interface" }, { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, + { "name": "GridKeyboardArrowRight", "kind": "Variable" }, { "name": "GridKeyGetterParams", "kind": "Interface" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, { "name": "GridLinkOperator", "kind": "Enum" }, @@ -374,7 +375,6 @@ { "name": "HideGridColMenuItem", "kind": "ExportSpecifier" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, - { "name": "KeyboardArrowRight", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, { "name": "Logger", "kind": "Interface" }, { "name": "MAX_PAGE_SIZE", "kind": "Variable" }, From 16de536e0eb13fea325c59d5d8b117b253791dc1 Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 3 Jan 2022 10:41:51 +0100 Subject: [PATCH 12/33] Work --- .../grid/hooks/features/rowGrouping/useGridRowGrouping.tsx | 1 - packages/grid/_modules_/grid/locales/fiFI.ts | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 84b156333f858..1db344bc99d9f 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -458,7 +458,6 @@ export const useGridRowGrouping = ( const lastGroupingColumnsModelApplied = sanitizedModelOnLastRowPreProcessing.current; if (!isDeepEqual(lastGroupingColumnsModelApplied, rowGroupingModel)) { - console.log(lastGroupingColumnsModelApplied, rowGroupingModel) sanitizedModelOnLastRowPreProcessing.current = rowGroupingModel; // Refresh the column pre-processing diff --git a/packages/grid/_modules_/grid/locales/fiFI.ts b/packages/grid/_modules_/grid/locales/fiFI.ts index 8e05a45b1c343..80349576055c8 100644 --- a/packages/grid/_modules_/grid/locales/fiFI.ts +++ b/packages/grid/_modules_/grid/locales/fiFI.ts @@ -116,6 +116,11 @@ const fiFIGrid: Partial = { treeDataGroupingHeaderName: 'Ryhmä', treeDataExpand: 'Laajenna', treeDataCollapse: 'Supista', + + // Grouping columns + // groupingColumnHeaderName: 'Group', + // groupColumn: name => `Group by ${name}`, + // unGroupColumn: name => `Stop grouping by ${name}`, }; export const fiFI: Localization = getGridLocalization(fiFIGrid, fiFICore); From 2760d132aa2c3e3c1f1ffb739aafa9f4067ebd2f Mon Sep 17 00:00:00 2001 From: delangle Date: Mon, 3 Jan 2022 14:50:37 +0100 Subject: [PATCH 13/33] Code review: Matheus --- .../GridRowGroupableColumnMenuItems.tsx | 63 +++++++++++++++++ ...tsx => GridRowGroupingColumnMenuItems.tsx} | 69 +++---------------- .../rowGrouping/useGridRowGrouping.tsx | 22 +++++- 3 files changed, 90 insertions(+), 64 deletions(-) create mode 100644 packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupableColumnMenuItems.tsx rename packages/grid/_modules_/grid/components/menu/columnMenu/{GridRowGroupingMenuItems.tsx => GridRowGroupingColumnMenuItems.tsx} (54%) diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupableColumnMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupableColumnMenuItems.tsx new file mode 100644 index 0000000000000..1a064e2ad7a59 --- /dev/null +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupableColumnMenuItems.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import MenuItem from '@mui/material/MenuItem'; +import { useGridApiContext } from '../../../hooks/utils/useGridApiContext'; +import { GridColDef } from '../../../models/colDef/gridColDef'; +import { useGridSelector } from '../../../hooks/utils/useGridSelector'; +import { gridRowGroupingSanitizedModelSelector } from '../../../hooks/features/rowGrouping/gridRowGroupingSelector'; +import { gridColumnLookupSelector } from '../../../hooks/features/columns/gridColumnsSelector'; + +interface GridRowGroupableColumnMenuItemsProps { + column?: GridColDef; + onClick?: (event: React.MouseEvent) => void; +} + +const GridRowGroupableColumnMenuItems = (props: GridRowGroupableColumnMenuItemsProps) => { + const { column, onClick } = props; + const apiRef = useGridApiContext(); + const rowGroupingModel = useGridSelector(apiRef, gridRowGroupingSanitizedModelSelector); + const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector); + + if (!column?.groupable) { + return null; + } + + const ungroupColumn = (event: React.MouseEvent) => { + apiRef.current.removeRowGroupingCriteria(column.field); + if (onClick) { + onClick(event); + } + }; + + const groupColumn = (event: React.MouseEvent) => { + apiRef.current.addRowGroupingCriteria(column.field); + if (onClick) { + onClick(event); + } + }; + + const name = columnsLookup[column.field].headerName ?? column.field; + + if (rowGroupingModel.includes(column.field)) { + return ( + + {apiRef.current.getLocaleText('unGroupColumn')(name)} + + ); + } + + return ( + {apiRef.current.getLocaleText('groupColumn')(name)} + ); +}; + +GridRowGroupableColumnMenuItems.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "yarn proptypes" | + // ---------------------------------------------------------------------- + column: PropTypes.object, + onClick: PropTypes.func, +} as any; + +export { GridRowGroupableColumnMenuItems }; diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx similarity index 54% rename from packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx rename to packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx index 8f60f6ef79ef9..e53381ca33468 100644 --- a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingMenuItems.tsx +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import MenuItem from '@mui/material/MenuItem'; -import Divider from '@mui/material/Divider'; import { useGridApiContext } from '../../../hooks/utils/useGridApiContext'; import { GridColDef } from '../../../models/colDef/gridColDef'; import { useGridSelector } from '../../../hooks/utils/useGridSelector'; @@ -13,37 +12,17 @@ import { } from '../../../hooks/features/rowGrouping/gridRowGroupingUtils'; import { gridColumnLookupSelector } from '../../../hooks/features/columns/gridColumnsSelector'; -interface GridGroupingColumnsMenuItemsProps { +interface GridRowGroupingColumnMenuItemsProps { column?: GridColDef; onClick?: (event: React.MouseEvent) => void; } -const GridRowGroupingMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { +const GridRowGroupingColumnMenuItems = (props: GridRowGroupingColumnMenuItemsProps) => { const { column, onClick } = props; const apiRef = useGridApiContext(); const rowGroupingModel = useGridSelector(apiRef, gridRowGroupingSanitizedModelSelector); const columnsLookup = useGridSelector(apiRef, gridColumnLookupSelector); - const isGrouped = React.useMemo( - () => column?.field && rowGroupingModel.includes(column.field), - [column, rowGroupingModel], - ); - - const renderGroupingMenuItem = (field: string) => { - const name = columnsLookup[field].headerName ?? field; - - const groupColumn = (event: React.MouseEvent) => { - apiRef.current.addRowGroupingCriteria(field); - if (onClick) { - onClick(event); - } - }; - - return ( - {apiRef.current.getLocaleText('groupColumn')(name)} - ); - }; - const renderUnGroupingMenuItem = (field: string) => { const ungroupColumn = (event: React.MouseEvent) => { apiRef.current.removeRowGroupingCriteria(field); @@ -61,50 +40,18 @@ const GridRowGroupingMenuItems = (props: GridGroupingColumnsMenuItemsProps) => { ); }; - if (!column) { + if (!column || !isGroupingColumn(column.field)) { return null; } - if (isGroupingColumn(column.field)) { - if (column.field === GROUPING_COLUMN_SINGLE) { - return ( - - - {rowGroupingModel.map(renderUnGroupingMenuItem)} - - ); - } - - return ( - - - {renderUnGroupingMenuItem(getGroupingCriteriaFieldFromGroupingColDefField(column.field)!)} - - ); - } - - if (isGrouped) { - return ( - - - {renderUnGroupingMenuItem(column.field)} - - ); - } - - if (!column.groupable) { - return null; + if (column.field === GROUPING_COLUMN_SINGLE) { + return {rowGroupingModel.map(renderUnGroupingMenuItem)}; } - return ( - - - {renderGroupingMenuItem(column.field)} - - ); + return renderUnGroupingMenuItem(getGroupingCriteriaFieldFromGroupingColDefField(column.field)!); }; -GridRowGroupingMenuItems.propTypes = { +GridRowGroupingColumnMenuItems.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | @@ -113,4 +60,4 @@ GridRowGroupingMenuItems.propTypes = { onClick: PropTypes.func, } as any; -export { GridRowGroupingMenuItems }; +export { GridRowGroupingColumnMenuItems }; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 1db344bc99d9f..c138328247070 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import Divider from '@mui/material/Divider'; import type { GridApiRef, GridRowModel, @@ -7,6 +8,7 @@ import type { GridKeyValue, GridCellValue, GridValueGetterSimpleParams, + GridStateColDef, } from '../../../models'; import { GridEvents, GridEventListener } from '../../../models/events'; import { GridRowGroupingPreProcessing } from '../../core/rowGroupsPerProcessing'; @@ -43,7 +45,8 @@ import { useGridStateInit } from '../../utils/useGridStateInit'; import { GridRowGroupingApi, GridRowGroupingModel } from './gridRowGroupingInterfaces'; import { useGridApiMethod } from '../../utils'; import { gridColumnLookupSelector } from '../columns'; -import { GridRowGroupingMenuItems } from '../../../components/menu/columnMenu/GridRowGroupingMenuItems'; +import { GridRowGroupableColumnMenuItems } from '../../../components/menu/columnMenu/GridRowGroupableColumnMenuItems'; +import { GridRowGroupingColumnMenuItems } from '../../../components/menu/columnMenu/GridRowGroupingColumnMenuItems'; /** * Only available in DataGridPro @@ -301,12 +304,25 @@ export const useGridRowGrouping = ( ); const addColumnMenuButtons = React.useCallback( - (initialValue: JSX.Element[]) => { + (initialValue: JSX.Element[], columns: GridStateColDef) => { if (props.disableRowGrouping) { return initialValue; } - return [...initialValue, ]; + let menuItems: React.ReactNode; + if (isGroupingColumn(columns.field)) { + menuItems = ; + } else if (columns.groupable) { + menuItems = ; + } else { + menuItems = null; + } + + if (menuItems == null) { + return initialValue; + } + + return [...initialValue, , menuItems]; }, [props.disableRowGrouping], ); From 32c991eccecdfe7b5eaf6b5e0e35a9edb8c5a8a7 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Thu, 6 Jan 2022 13:07:54 +0100 Subject: [PATCH 14/33] Update packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> --- .../grid/components/cell/GridGroupingCriteriaCell.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx index d6230fcd20b5d..ae0c4cb716e3e 100644 --- a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx @@ -51,9 +51,7 @@ const GridGroupingCriteriaCell = (props: GridGroupingCriteriaCellProps) => { if (event.key === ' ') { event.stopPropagation(); } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); - } + apiRef.current.publishEvent(GridEvents.cellKeyDown, props, event); }; const handleClick = (event: React.MouseEvent) => { From 5dee1fb3e4850d780d51eefd12e86e036ecbd37d Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 6 Jan 2022 13:26:30 +0100 Subject: [PATCH 15/33] Code review: Matheus --- .../columnReorder/useGridColumnReorder.tsx | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/packages/grid/_modules_/grid/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/_modules_/grid/hooks/features/columnReorder/useGridColumnReorder.tsx index fd78aced48fe8..2f701e227cbc7 100644 --- a/packages/grid/_modules_/grid/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/_modules_/grid/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -138,17 +138,7 @@ export const useGridColumnReorder = ( const targetColVisibleIndex = apiRef.current.getColumnIndex(params.field, true); const targetCol = apiRef.current.getColumn(params.field); const dragColIndex = apiRef.current.getColumnIndex(dragColField, false); - const visibleColumnAmount = apiRef.current.getVisibleColumns().length; - - const canBeReordered = - !targetCol.disableReorder || - (targetColVisibleIndex > 0 && targetColVisibleIndex < visibleColumnAmount - 1); - - const canBeReorderedProcessed = apiRef.current.unstable_applyPreProcessors( - GridPreProcessingGroup.canBeReordered, - canBeReordered, - { targetIndex: targetColVisibleIndex }, - ); + const visibleColumns = apiRef.current.getVisibleColumns(); const cursorMoveDirectionX = getCursorMoveDirectionX(cursorPosition.current, coordinates); const hasMovedLeft = @@ -156,8 +146,28 @@ export const useGridColumnReorder = ( const hasMovedRight = cursorMoveDirectionX === CURSOR_MOVE_DIRECTION_RIGHT && dragColIndex < targetColIndex; - if (canBeReorderedProcessed && (hasMovedLeft || hasMovedRight)) { - apiRef.current.setColumnIndex(dragColField, targetColIndex); + if (hasMovedLeft || hasMovedRight) { + let canBeReordered: boolean; + if (!targetCol.disableReorder) { + canBeReordered = true; + } else if (hasMovedLeft) { + canBeReordered = + targetColIndex > 0 && !visibleColumns[targetColIndex - 1].disableReorder; + } else { + canBeReordered = + targetColIndex < visibleColumns.length - 1 && + !visibleColumns[targetColIndex + 1].disableReorder; + } + + const canBeReorderedProcessed = apiRef.current.unstable_applyPreProcessors( + GridPreProcessingGroup.canBeReordered, + canBeReordered, + { targetIndex: targetColVisibleIndex }, + ); + + if (canBeReorderedProcessed) { + apiRef.current.setColumnIndex(dragColField, targetColIndex); + } } cursorPosition.current = coordinates; From e63926d4ad742e1b21ca5ca26a7aaadba6c2091a Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 6 Jan 2022 13:29:00 +0100 Subject: [PATCH 16/33] Fix lint --- .../_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx index ae0c4cb716e3e..61bb75a2d80e1 100644 --- a/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx +++ b/packages/grid/_modules_/grid/components/cell/GridGroupingCriteriaCell.tsx @@ -8,7 +8,6 @@ import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { GridRenderCellParams } from '../../models/params/gridCellParams'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; import { gridFilteredDescendantCountLookupSelector } from '../../hooks/features/filter/gridFilterSelector'; -import { isNavigationKey } from '../../utils/keyboardUtils'; import { GridEvents } from '../../models/events'; import { getDataGridUtilityClass } from '../../gridClasses'; import { DataGridProProcessedProps } from '../../models/props/DataGridProProps'; From 3d5d9654660aa8af45a69ab4385752f2028d9473 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 11 Jan 2022 12:51:29 +0100 Subject: [PATCH 17/33] Fix --- docs/pages/api-docs/data-grid/grid-filter-item.js | 2 +- docs/pages/api-docs/data-grid/grid-filter-model.js | 2 +- docs/pages/api-docs/data-grid/grid-filter-operator.js | 2 +- .../x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/pages/api-docs/data-grid/grid-filter-item.js b/docs/pages/api-docs/data-grid/grid-filter-item.js index 96177a43fd67e..5155144ea50ef 100644 --- a/docs/pages/api-docs/data-grid/grid-filter-item.js +++ b/docs/pages/api-docs/data-grid/grid-filter-item.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import MarkdownDocs from '@material-ui/monorepo/docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from '@mui/monorepo/docs/src/modules/components/MarkdownDocs'; import { demos, docs, demoComponents } from './grid-filter-item.md?@mui/markdown'; export default function Page() { diff --git a/docs/pages/api-docs/data-grid/grid-filter-model.js b/docs/pages/api-docs/data-grid/grid-filter-model.js index 35447b4d301a4..61239d3ad426f 100644 --- a/docs/pages/api-docs/data-grid/grid-filter-model.js +++ b/docs/pages/api-docs/data-grid/grid-filter-model.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import MarkdownDocs from '@material-ui/monorepo/docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from '@mui/monorepo/docs/src/modules/components/MarkdownDocs'; import { demos, docs, demoComponents } from './grid-filter-model.md?@mui/markdown'; export default function Page() { diff --git a/docs/pages/api-docs/data-grid/grid-filter-operator.js b/docs/pages/api-docs/data-grid/grid-filter-operator.js index 83ab3cae12fa9..2cbd12ae534ef 100644 --- a/docs/pages/api-docs/data-grid/grid-filter-operator.js +++ b/docs/pages/api-docs/data-grid/grid-filter-operator.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import MarkdownDocs from '@material-ui/monorepo/docs/src/modules/components/MarkdownDocs'; +import MarkdownDocs from '@mui/monorepo/docs/src/modules/components/MarkdownDocs'; import { demos, docs, demoComponents } from './grid-filter-operator.md?@mui/markdown'; export default function Page() { diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index 8e78b10ac8f3f..c53d52d22879f 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -1,4 +1,4 @@ -import { createRenderer, fireEvent, screen, act } from '@material-ui/monorepo/test/utils'; +import { createRenderer, fireEvent, screen, act } from '@mui/monorepo/test/utils'; import { getColumnHeadersTextContent, getColumnValues } from 'test/utils/helperFn'; import * as React from 'react'; import { expect } from 'chai'; From e4514332ebccbc396c9cab63149b9ddbd26ee6a6 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 11 Jan 2022 14:30:09 +0100 Subject: [PATCH 18/33] Md lint --- docs/src/pages/components/data-grid/filtering/filtering.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/pages/components/data-grid/filtering/filtering.md b/docs/src/pages/components/data-grid/filtering/filtering.md index b09eb3018257a..c9aa5124de3b8 100644 --- a/docs/src/pages/components/data-grid/filtering/filtering.md +++ b/docs/src/pages/components/data-grid/filtering/filtering.md @@ -147,7 +147,7 @@ You can get them by importing the following functions: | `number` | `getGridNumericOperators()` | | `boolean` | `getGridBooleanOperators()` | | `date` | `getGridDateOperators()` | -| `dateTime ` | `getGridDateOperators(true)` | +| `dateTime` | `getGridDateOperators(true)` | | `singleSelect` | `getGridSingleSelectOperators()` | You can find more information about the supported column types in the [columns section](/components/data-grid/columns/#column-types). From 6fcdecc5ca5c6e650de73c1209ffc89cd6ced8d7 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 11 Jan 2022 17:08:21 +0100 Subject: [PATCH 19/33] Work --- docs/pages/api-docs/data-grid/selectors.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/pages/api-docs/data-grid/selectors.json b/docs/pages/api-docs/data-grid/selectors.json index f3b49372df0aa..fdc17bd8b1d63 100644 --- a/docs/pages/api-docs/data-grid/selectors.json +++ b/docs/pages/api-docs/data-grid/selectors.json @@ -81,7 +81,18 @@ }, { "name": "gridResizingColumnFieldSelector", "returnType": "string", "description": "" }, { "name": "gridRowCountSelector", "returnType": "number", "description": "" }, + { + "name": "gridRowGroupingModelSelector", + "returnType": "GridRowGroupingModel", + "description": "" + }, { "name": "gridRowGroupingNameSelector", "returnType": "string", "description": "" }, + { "name": "gridRowGroupingSanitizedModelSelector", "returnType": "string[]", "description": "" }, + { + "name": "gridRowGroupingStateSelector", + "returnType": "GridRowGroupingState", + "description": "" + }, { "name": "gridRowIdsSelector", "returnType": "GridRowId[]", "description": "" }, { "name": "gridRowTreeDepthSelector", "returnType": "number", "description": "" }, { "name": "gridRowTreeSelector", "returnType": "GridRowTreeConfig", "description": "" }, From 57bf755f94257dd43594d2441ae68200c35e670f Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 12 Jan 2022 13:08:18 +0100 Subject: [PATCH 20/33] Code review: Alexandre --- .../rowGrouping/useGridRowGrouping.tsx | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 6860e82373621..2ed20c30fb472 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -33,7 +33,7 @@ import { } from './createGroupingColDef'; import { isDeepEqual } from '../../../utils/utils'; import { GridPreProcessingGroup, useGridRegisterPreProcessor } from '../../core/preProcessing'; -import { GridColumnsRawState } from '../columns/gridColumnsState'; +import { GridColumnRawLookup, GridColumnsRawState } from '../columns/gridColumnsState'; import { useGridRegisterFilteringMethod } from '../filter/useGridRegisterFilteringMethod'; import { GridFilteringMethod } from '../filter/gridFilterState'; import { gridRowIdsSelector, gridRowTreeSelector } from '../rows'; @@ -275,29 +275,37 @@ export const useGridRowGrouping = ( const updateGroupingColumn = React.useCallback( (columnsState: GridColumnsRawState) => { const groupingColDefs = getGroupingColDefs(columnsState); + let newColumnFields: string[] = []; + const newColumnsLookup: GridColumnRawLookup = {}; - // We remove the grouping columns - const newColumnFields: string[] = []; + // We only keep the non-grouping columns columnsState.all.forEach((field) => { - if (isGroupingColumn(field)) { - delete columnsState.lookup[field]; - } else { + if (!isGroupingColumn(field)) { newColumnFields.push(field); + newColumnsLookup[field] = columnsState.lookup[field]; } }); - columnsState.all = newColumnFields; // We add the grouping column groupingColDefs.forEach((groupingColDef) => { - columnsState.lookup[groupingColDef.field] = groupingColDef; + const matchingGroupingColDef = columnsState.lookup[groupingColDef.field]; + if (matchingGroupingColDef) { + groupingColDef.width = matchingGroupingColDef.width; + groupingColDef.flex = matchingGroupingColDef.flex; + } + + newColumnsLookup[groupingColDef.field] = groupingColDef; }); - const startIndex = columnsState.all[0] === '__check__' ? 1 : 0; - columnsState.all = [ - ...columnsState.all.slice(0, startIndex), + const startIndex = newColumnFields[0] === '__check__' ? 1 : 0; + newColumnFields = [ + ...newColumnFields.slice(0, startIndex), ...groupingColDefs.map((colDef) => colDef.field), - ...columnsState.all.slice(startIndex), + ...newColumnFields.slice(startIndex), ]; + columnsState.all = newColumnFields; + columnsState.lookup = newColumnsLookup; + return columnsState; }, [getGroupingColDefs], From 392ddebad197cd40ed7eadba071d287cc0789e25 Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 12 Jan 2022 16:36:01 +0100 Subject: [PATCH 21/33] Work --- .../GridRowGroupingColumnMenuItems.tsx | 8 +- .../rowGrouping/createGroupingColDef.tsx | 9 +- .../rowGrouping/gridRowGroupingUtils.ts | 18 +- .../grid/hooks/features/rowGrouping/index.ts | 4 + .../rowGrouping/useGridRowGrouping.tsx | 5 +- .../tests/rowGrouping.DataGridPro.test.tsx | 160 +++++++++++++++--- 6 files changed, 159 insertions(+), 45 deletions(-) diff --git a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx index e53381ca33468..01285b97b15a6 100644 --- a/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx +++ b/packages/grid/_modules_/grid/components/menu/columnMenu/GridRowGroupingColumnMenuItems.tsx @@ -6,8 +6,8 @@ import { GridColDef } from '../../../models/colDef/gridColDef'; import { useGridSelector } from '../../../hooks/utils/useGridSelector'; import { gridRowGroupingSanitizedModelSelector } from '../../../hooks/features/rowGrouping/gridRowGroupingSelector'; import { - getGroupingCriteriaFieldFromGroupingColDefField, - GROUPING_COLUMN_SINGLE, + getRowGroupingCriteriaFromGroupingField, + GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, isGroupingColumn, } from '../../../hooks/features/rowGrouping/gridRowGroupingUtils'; import { gridColumnLookupSelector } from '../../../hooks/features/columns/gridColumnsSelector'; @@ -44,11 +44,11 @@ const GridRowGroupingColumnMenuItems = (props: GridRowGroupingColumnMenuItemsPro return null; } - if (column.field === GROUPING_COLUMN_SINGLE) { + if (column.field === GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD) { return {rowGroupingModel.map(renderUnGroupingMenuItem)}; } - return renderUnGroupingMenuItem(getGroupingCriteriaFieldFromGroupingColDefField(column.field)!); + return renderUnGroupingMenuItem(getRowGroupingCriteriaFromGroupingField(column.field)!); }; GridRowGroupingColumnMenuItems.propTypes = { diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx index 30d5245a5c13c..2e47e88a95088 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -12,7 +12,10 @@ import { import { GridColumnRawLookup } from '../columns/gridColumnsState'; import { GridGroupingCriteriaCell } from '../../../components/cell/GridGroupingCriteriaCell'; import { GridGroupingColumnLeafCell } from '../../../components/cell/GridGroupingColumnLeafCell'; -import { getGroupingColDefFieldFromGroupingCriteriaField } from './gridRowGroupingUtils'; +import { + getRowGroupingFieldFromGroupingCriteria, + GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, +} from './gridRowGroupingUtils'; import { gridRowGroupingSanitizedModelSelector } from './gridRowGroupingSelector'; const GROUPING_COL_DEF_DEFAULT_PROPERTIES: Omit = { @@ -234,7 +237,7 @@ export const createGroupingColDefForOneGroupingCriteria = ({ // The properties that can't be overridden with `colDefOverride` const forcedProperties: Pick = { - field: getGroupingColDefFieldFromGroupingCriteriaField(groupingCriteria), + field: getRowGroupingFieldFromGroupingCriteria(groupingCriteria), ...GROUPING_COL_DEF_FORCED_PROPERTIES, }; @@ -346,7 +349,7 @@ export const createGroupingColDefForAllGroupingCriteria = ({ // The properties that can't be overridden with `colDefOverride` const forcedProperties: Pick = { - field: getGroupingColDefFieldFromGroupingCriteriaField(null), + field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, ...GROUPING_COL_DEF_FORCED_PROPERTIES, }; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts index c682b437986d6..b6be5ff662e1d 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts @@ -8,21 +8,19 @@ import { GridFilterState } from '../filter'; import { DataGridProProcessedProps } from '../../../models/props/DataGridProProps'; import { GridAggregatedFilterItemApplier } from '../filter/gridFilterState'; -export const GROUPING_COLUMN_SINGLE = '__row_group_by_columns_group__'; +export const GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD = '__row_group_by_columns_group__'; export const GROUPING_COLUMNS_FEATURE_NAME = 'grouping-columns'; -export const getGroupingColDefFieldFromGroupingCriteriaField = ( - groupingCriteria: string | null, -) => { +export const getRowGroupingFieldFromGroupingCriteria = (groupingCriteria: string) => { if (groupingCriteria === null) { - return GROUPING_COLUMN_SINGLE; + return GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD; } return `__row_group_by_columns_group_${groupingCriteria}__`; }; -export const getGroupingCriteriaFieldFromGroupingColDefField = (groupingColDefField: string) => { +export const getRowGroupingCriteriaFromGroupingField = (groupingColDefField: string) => { const match = groupingColDefField.match(/^__row_group_by_columns_group_(.*)__$/); if (!match) { @@ -33,8 +31,8 @@ export const getGroupingCriteriaFieldFromGroupingColDefField = (groupingColDefFi }; export const isGroupingColumn = (field: string) => - field === GROUPING_COLUMN_SINGLE || - getGroupingCriteriaFieldFromGroupingColDefField(field) !== null; + field === GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD || + getRowGroupingCriteriaFromGroupingField(field) !== null; interface FilterRowTreeFromTreeDataParams { rowTree: GridRowTreeConfig; @@ -45,11 +43,11 @@ interface FilterRowTreeFromTreeDataParams { * When filtering a group, we only want to filter according to the items related to this grouping column. */ const shouldApplyFilterItemOnGroup = (item: GridFilterItem, node: GridRowTreeNodeConfig) => { - if (item.columnField === GROUPING_COLUMN_SINGLE) { + if (item.columnField === GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD) { return true; } - const groupingCriteriaField = getGroupingCriteriaFieldFromGroupingColDefField(item.columnField); + const groupingCriteriaField = getRowGroupingCriteriaFromGroupingField(item.columnField); return groupingCriteriaField === node.groupingField; }; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts index 387f4cae74ed4..4a716de788980 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/index.ts @@ -1,2 +1,6 @@ export * from './gridRowGroupingSelector'; export * from './gridRowGroupingInterfaces'; +export { + GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, + getRowGroupingFieldFromGroupingCriteria, +} from './gridRowGroupingUtils'; diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index 2ed20c30fb472..c5d06fa64fe78 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -22,7 +22,7 @@ import { import { DataGridProProcessedProps } from '../../../models/props/DataGridProProps'; import { filterRowTreeFromGroupingColumns, - getGroupingColDefFieldFromGroupingCriteriaField, + getRowGroupingFieldFromGroupingCriteria, getColDefOverrides, GROUPING_COLUMNS_FEATURE_NAME, isGroupingColumn, @@ -463,8 +463,7 @@ export const useGridRowGrouping = ( const isOnGroupingCell = props.rowGroupingColumnMode === 'single' || - getGroupingColDefFieldFromGroupingCriteriaField(params.rowNode.groupingField) === - params.field; + getRowGroupingFieldFromGroupingCriteria(params.rowNode.groupingField) === params.field; if (!isOnGroupingCell || filteredDescendantCount === 0) { return; } diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index c53d52d22879f..6284b33de2b43 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -1,10 +1,16 @@ import { createRenderer, fireEvent, screen, act } from '@mui/monorepo/test/utils'; -import { getColumnHeadersTextContent, getColumnValues } from 'test/utils/helperFn'; +import { + getColumnHeaderCell, + getColumnHeadersTextContent, + getColumnValues, +} from 'test/utils/helperFn'; import * as React from 'react'; import { expect } from 'chai'; import { DataGridPro, DataGridProProps, + getRowGroupingFieldFromGroupingCriteria, + GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, GridApiRef, GridKeyGetterParams, GridPreferencePanelsValue, @@ -56,7 +62,7 @@ const baselineProps: DataGridProProps = { }, }; -describe(' - Group Rows By Column', () => { +describe.only(' - Group Rows By Column', () => { const { render, clock } = createRenderer({ clock: 'fake' }); let apiRef: GridApiRef; @@ -701,38 +707,42 @@ describe(' - Group Rows By Column', () => { describe('props: groupingColDef when groupingColumMode = "single"', () => { it('should not allow to override the field', () => { + render( + , + ); + + expect(apiRef.current.getAllColumns()[0].field).to.equal('__row_group_by_columns_group__'); + }); + + it('should react to groupingColDef update', () => { const { setProps } = render( - params.fields.includes('category1') - ? { - headerName: 'Custom group', - } - : {} - } + initialState={{ rowGrouping: { model: ['category1'] } }} + rowGroupingColumnMode="single" + groupingColDef={{}} />, ); expect(getColumnHeadersTextContent()).to.deep.equal([ - 'Custom group', - 'category2', + 'category1', 'id', 'category1', 'category2', ]); setProps({ - groupingColDef: (params) => - params.fields.includes('category2') - ? { - headerName: 'Custom group', - } - : {}, + groupingColDef: { + headerName: 'Custom group', + }, }); expect(getColumnHeadersTextContent()).to.deep.equal([ - 'category1', 'Custom group', 'id', 'category1', @@ -740,7 +750,31 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should react to groupingColDef update', () => {}); + it('should keep the grouping column width between generations', () => { + render( + , + ); + + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '200px' }); + apiRef.current.updateColumns([ + { field: GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, width: 100 }, + ]); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '100px' }); + apiRef.current.updateColumns([ + { + field: 'id', + headerName: 'New id', + }, + ]); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '100px' }); + }); describe('prop: groupColDef.leafField', () => { it('should render the leafField `value` on leaves', () => { @@ -939,7 +973,7 @@ describe(' - Group Rows By Column', () => { render( - Group Rows By Column', () => { />, ); - expect(apiRef.current.getAllColumns()[0].field).to.equal('__row_group_by_columns_group__'); + expect(apiRef.current.getAllColumns()[0].field).to.equal( + '__row_group_by_columns_group_category1__', + ); + }); + + it('should react to groupingColDef update', () => { + const { setProps } = render( + + params.fields.includes('category1') + ? { + headerName: 'Custom group', + } + : {} + } + />, + ); + + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'Custom group', + 'category2', + 'id', + 'category1', + 'category2', + ]); + + setProps({ + groupingColDef: (params) => + params.fields.includes('category2') + ? { + headerName: 'Custom group', + } + : {}, + }); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'category1', + 'Custom group', + 'id', + 'category1', + 'category2', + ]); + }); + + it('should keep the grouping column width between generations', () => { + render( + + params.fields.includes('category1') ? { width: 200 } : { width: 300 } + } + />, + ); + + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '200px' }); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(1)).toHaveInlineStyle({ width: '300px' }); + apiRef.current.updateColumns([ + { field: getRowGroupingFieldFromGroupingCriteria('category1'), width: 100 }, + ]); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '100px' }); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(1)).toHaveInlineStyle({ width: '300px' }); + apiRef.current.updateColumns([ + { + field: 'id', + headerName: 'New id', + }, + ]); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(0)).toHaveInlineStyle({ width: '100px' }); + // @ts-expect-error need to migrate helpers to TypeScript + expect(getColumnHeaderCell(1)).toHaveInlineStyle({ width: '300px' }); }); describe('prop: groupColDef.leafField', () => { @@ -1646,7 +1756,7 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should sort unbalanced grouped by index of the groupingField in the model when sorting by a grouping criteria', () => { + it('should sort unbalanced grouped by index of the grouping criteria in the model when sorting by a grouping criteria', () => { render( - Group Rows By Column', () => { ]); }); - it('should sort unbalanced grouped by index of the groupingField in the model when sorting by leaves', () => { + it('should sort unbalanced grouped by index of the grouping criteria in the model when sorting by leaves', () => { render( Date: Wed, 12 Jan 2022 16:39:24 +0100 Subject: [PATCH 22/33] Work --- .../grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts index b6be5ff662e1d..be89667aaf8b9 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingUtils.ts @@ -12,7 +12,7 @@ export const GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD = '__row_group_by_columns_g export const GROUPING_COLUMNS_FEATURE_NAME = 'grouping-columns'; -export const getRowGroupingFieldFromGroupingCriteria = (groupingCriteria: string) => { +export const getRowGroupingFieldFromGroupingCriteria = (groupingCriteria: string | null) => { if (groupingCriteria === null) { return GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD; } From 849699cebddf3ea0d4c47eae13b8a6f2aed975da Mon Sep 17 00:00:00 2001 From: delangle Date: Wed, 12 Jan 2022 16:48:05 +0100 Subject: [PATCH 23/33] Fix --- .../x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx | 2 +- scripts/x-data-grid-pro.exports.json | 2 ++ scripts/x-data-grid.exports.json | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index 6284b33de2b43..7e081f27e4cbe 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -62,7 +62,7 @@ const baselineProps: DataGridProProps = { }, }; -describe.only(' - Group Rows By Column', () => { +describe(' - Group Rows By Column', () => { const { render, clock } = createRenderer({ clock: 'fake' }); let apiRef: GridApiRef; diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 82d79352f92bc..e446f0b3b8f60 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -32,6 +32,7 @@ { "name": "getGridNumericOperators", "kind": "Variable" }, { "name": "getGridSingleSelectOperators", "kind": "Variable" }, { "name": "getGridStringOperators", "kind": "Variable" }, + { "name": "getRowGroupingFieldFromGroupingCriteria", "kind": "ExportSpecifier" }, { "name": "GRID_ACTIONS_COL_DEF", "kind": "Variable" }, { "name": "GRID_BOOLEAN_COL_DEF", "kind": "Variable" }, { "name": "GRID_CHECKBOX_SELECTION_COL_DEF", "kind": "Variable" }, @@ -40,6 +41,7 @@ { "name": "GRID_DEFAULT_LOCALE_TEXT", "kind": "Variable" }, { "name": "GRID_EXPERIMENTAL_ENABLED", "kind": "Variable" }, { "name": "GRID_NUMERIC_COL_DEF", "kind": "Variable" }, + { "name": "GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD", "kind": "ExportSpecifier" }, { "name": "GRID_SINGLE_SELECT_COL_DEF", "kind": "Variable" }, { "name": "GRID_STRING_COL_DEF", "kind": "Variable" }, { "name": "GRID_TREE_DATA_GROUPING_FIELD", "kind": "ExportSpecifier" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index ce8122bfac40c..f5581b63e7eb9 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -32,6 +32,7 @@ { "name": "getGridNumericOperators", "kind": "Variable" }, { "name": "getGridSingleSelectOperators", "kind": "Variable" }, { "name": "getGridStringOperators", "kind": "Variable" }, + { "name": "getRowGroupingFieldFromGroupingCriteria", "kind": "ExportSpecifier" }, { "name": "GRID_ACTIONS_COL_DEF", "kind": "Variable" }, { "name": "GRID_BOOLEAN_COL_DEF", "kind": "Variable" }, { "name": "GRID_CHECKBOX_SELECTION_COL_DEF", "kind": "Variable" }, @@ -40,6 +41,7 @@ { "name": "GRID_DEFAULT_LOCALE_TEXT", "kind": "Variable" }, { "name": "GRID_EXPERIMENTAL_ENABLED", "kind": "Variable" }, { "name": "GRID_NUMERIC_COL_DEF", "kind": "Variable" }, + { "name": "GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD", "kind": "ExportSpecifier" }, { "name": "GRID_SINGLE_SELECT_COL_DEF", "kind": "Variable" }, { "name": "GRID_STRING_COL_DEF", "kind": "Variable" }, { "name": "GRID_TREE_DATA_GROUPING_FIELD", "kind": "ExportSpecifier" }, From f6c10a9e1041ae431c1e4313b3cd0e15fd653927 Mon Sep 17 00:00:00 2001 From: delangle Date: Thu, 13 Jan 2022 15:40:53 +0100 Subject: [PATCH 24/33] Code review: Jose & Matheus part 1 --- .../data-grid/group-pivot/group-pivot.md | 77 ++++++++++--------- .../rowGrouping/createGroupingColDef.tsx | 3 - .../rowGrouping/gridRowGroupingInterfaces.ts | 3 - .../grid/models/gridIconSlotsComponent.ts | 4 +- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 27d82fed55e57..3db2e177955d9 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -8,7 +8,7 @@ title: Data Grid - Group & Pivot ## Row grouping [](https://mui.com/store/items/material-ui-pro/) -Use row grouping to group the rows according to one or several columns value

+Use row grouping to group the rows according to one or several columns value. > ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. > @@ -24,12 +24,12 @@ Use row grouping to group the rows according to one or several columns value

#### Initialize the row grouping -To initialize the row grouping without controlling it, provide the model to the `initialState` prop: +The easiest way to get started with the feature is to provide its model to the `initialState` prop: ```ts initialState={{ rowGrouping: { - model: ['director', 'category'] + model: ['company', 'director'], } }} ``` @@ -38,58 +38,43 @@ initialState={{ #### Controlled row grouping -Use the `rowGroupingModel` prop to control the criteria used to group the rows. +If you need to control the state of the criteria used for grouping, use the `rowGroupingModel` prop. You can use the `onRowGroupingModelChange` prop to listen to changes to the page size and update the prop accordingly. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingControlled.js", "bg": "inline", "defaultCodeOpen": false}} -### Disable the row grouping - -#### For all columns - -To fully disable the grouping feature, set the `disableRowGrouping` prop to `true`. - -It will disable all the features related to the row grouping, even if a model is provided. - -{{"demo": "pages/components/data-grid/group-pivot/RowGroupingDisabled.js", "bg": "inline", "defaultCodeOpen": false}} - -#### For some columns - -To block the grouping of certain columns, set the `groupable` property of `GridColDef` to `false`. -In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. - -{{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} - ### Grouping columns #### Single grouping column -By default, the grid will create only one grouping column even if you have several grouping criteria. +By default, the grid will display a single column holding all grouped columns. +If you have multiple grouped columns, this column name will be set to "Group". {{"demo": "pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} #### Multiple grouping column -To have a grouping column for each grouping criteria, set the `rowGroupingColumnMode` prop to `multiple`. +To display a column for each grouping criterion, set the `rowGroupingColumnMode` prop to `multiple. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} #### Custom grouping column -Use the `groupingColDef` prop to customize the rendering of the grouping column. You can override any property of the `GridColDef` interface except the `field`, the `type` and the properties related to the edition. - -If you want to apply your overrides to every grouping column, use the object format of `groupingColDef`. +To customize the rendering of the grouping column, use the `groupingColDef` prop. +You can override the **headerName** or any property of the `GridColDef` interface, except the `field`, the `type` and the properties related to inline edition. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefObject.js", "bg": "inline", "defaultCodeOpen": false}} -If you want to only override properties of certain grouping columns or to apply different overrides based on the current grouping criteria, use the callback format of `groupingColDef`. -It will be called for each grouping column with the fields of the columns used to build it. +By default, when using the object format, the properties will be applied to all Grouping columns. This means that if you have `rowGroupingColumnMode` set to `multiple`, all the columns will share the same `groupingColDef` properties. + +If you wish to override properties of specific grouping columns or to apply different overrides based on the current grouping criteria, you can pass a callback function to `groupingColDef`, instead of an object with its config. +The callback is called for each grouping column, and it receives the respective column's "fields" as parameter. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingCustomGroupingColDefCallback.js", "bg": "inline", "defaultCodeOpen": false}} #### Show values for the leaves -By default, the leaves nodes don't render anything for their grouping cell. +By default, the grouped rows display no value on their grouping columns' cells. We're calling those cells "leaves". If you want to display some value, you can provide a `leafField` property to the `groupingColDef`. @@ -97,16 +82,32 @@ If you want to display some value, you can provide a `leafField` property to the #### Hide the descendant count -You can use the `hideDescendantCount` property of the `groupingColDef` to hide the amount of descendant of a grouping row. +Use the `hideDescendantCount` property of the `groupingColDef to hide the number of descendants of a grouping row. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js", "bg": "inline", "defaultCodeOpen": false}} -### Complex grouping value +### Disable the row grouping + +#### For all columns + +You can disable row grouping by setting `disableRowGrouping` prop to true. + +It will disable all the features related to the row grouping, even if a model is provided. + +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingDisabled.js", "bg": "inline", "defaultCodeOpen": false}} + +#### For some columns + +In case you need to disable grouping on specific column(s), set the `groupable` property on the respective column definition (`GridColDef`) to `false`. +In the example below, the `director` column can not be grouped. And in all example, the `title` and `gross` columns can not be grouped. + +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} -In most scenarios, when you need to handle complex values, you provide a `valueGetter` property to your column definition. -But sometimes, you need to keep the object format for the `renderCell` property and thus can not convert it to a serializable value in `valueGetter`. +### Using 'keyGetter' for complex grouping value -You can then provide a `keyGetter` property in your column definition to convert this object into a serializable value. +In most scenarios, to handle complex values (e.g. nested structures), a `valueGetter` property must be provided to the column definition to convert it into a simple value. +But sometimes, you may want to keep the value in its raw format, to be used in a custom cell renderer, and thus using a value getter is not possible. +In this case, pass a `keyGetter` property to the column definition to convert this object into a serializable value. ```ts const columns: GridColumns = [ @@ -120,19 +121,19 @@ const columns: GridColumns = [ {{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js", "bg": "inline", "defaultCodeOpen": false}} -If your column also have a `valueGetter` property, the value passed to the `keyGetter` property will be the one returned by `valueGetter`. +**Note**: If your column also have a `valueGetter` property, its value is used as the parameter for the `keyGetter` method. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} ### Rows with missing groups -If the grouping key of a grouping criteria is `null` or `undefined` for a row, the grid will consider that this row do not have a value for this group. and will inline it for those groups. +If the grouping key of a grouping criteria is `null` or `undefined` for a row, the grid will consider that this row does not have a value for this group. and will inline it for those groups. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingRowsWithMissingGroups.js", "bg": "inline", "defaultCodeOpen": false}} ### Group expansion -Use the `defaultGroupingExpansionDepth` prop to expand all the groups up to a given depth when loading the data. +By default, all groups are initially displayed collapsed. You can change this behaviour by setting the `defaultGroupingExpansionDepth` prop to expand all the groups up to a given depth when loading the data. If you want to expand the whole tree, set `defaultGroupingExpansionDepth = -1` {{"demo": "pages/components/data-grid/group-pivot/RowGroupingDefaultExpansionDepth.js", "bg": "inline", "defaultCodeOpen": false}} @@ -262,7 +263,7 @@ If you want to access the grouping column field, for instance, to use it with co ### Group expansion -Same behavior as for the [Row grouping](#group-expansion) +Same behavior as for the [Row grouping](#group-expansion). ### Gaps in the tree diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx index 2e47e88a95088..ce4e976c595ea 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/createGroupingColDef.tsx @@ -134,17 +134,14 @@ const getGroupingCriteriaProperties = (groupedByColDef: GridColDef, applyHeaderN interface CreateGroupingColDefMonoCriteriaParams { columnsLookup: GridColumnRawLookup; - /** * The field from which we are grouping the rows. */ groupingCriteria: string; - /** * The col def from which we are grouping the rows. */ groupedByColDef: GridColDef | GridStateColDef; - /** * The col def properties the user wants to override. * This value comes `prop.groupingColDef`. diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts index 6c2382be9265d..0c78c47e49e05 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/gridRowGroupingInterfaces.ts @@ -14,20 +14,17 @@ export interface GridRowGroupingApi { * @param {GridRowGroupingModel} model The columns to use as grouping criteria. */ setRowGroupingModel: (model: GridRowGroupingModel) => void; - /** * Adds the field to the row grouping model. * @param {string} groupingCriteriaField The field from which we want to group the rows. * @param {number | undefined} groupingIndex The grouping index at which we want to insert the new grouping criteria. By default, it will be inserted at the end of the model. */ addRowGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => void; - /** * sRemove the field from the row grouping model. * @param {string} groupingCriteriaField The field from which we want to stop grouping the rows. */ removeRowGroupingCriteria: (groupingCriteriaField: string) => void; - /** * Sets the grouping index of a grouping criteria. * @param {string} groupingCriteriaField The field of the grouping criteria from which we want to change the grouping index. diff --git a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts index 810fbf5d0b51d..b1d4b54d97c6e 100644 --- a/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts +++ b/packages/grid/_modules_/grid/models/gridIconSlotsComponent.ts @@ -82,7 +82,7 @@ export interface GridIconSlotsComponent { MoreActionsIcon: React.JSXElementConstructor; /** * Icon displayed on the tree data toggling column when the children are collapsed - * @default KeyboardArrowRight + * @default GridKeyboardArrowRight */ TreeDataExpandIcon: React.JSXElementConstructor; /** @@ -92,7 +92,7 @@ export interface GridIconSlotsComponent { TreeDataCollapseIcon: React.JSXElementConstructor; /** * Icon displayed on the grouping column when the children are collapsed - * @default KeyboardArrowRight + * @default GridKeyboardArrowRight */ GroupingCriteriaExpandIcon: React.JSXElementConstructor; /** From b47bef6735db5bb9c194d4497f5ba5b6967b7847 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 14 Jan 2022 10:08:52 +0100 Subject: [PATCH 25/33] Code review --- .../TreeDataCustomGroupingColumn.js | 258 ++++++++++++++++++ .../TreeDataCustomGroupingColumn.tsx | 197 +++++++++++++ .../TreeDataCustomGroupingColumn.tsx.preview | 7 + .../data-grid/group-pivot/group-pivot.md | 11 +- .../x-data-grid-generator/src/useMovieData.ts | 27 +- 5 files changed, 494 insertions(+), 6 deletions(-) create mode 100644 docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview diff --git a/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.js b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.js new file mode 100644 index 0000000000000..c802eb9eb7796 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.js @@ -0,0 +1,258 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { + DataGridPro, + useGridApiContext, + GridEvents, + useGridSelector, + gridFilteredDescendantCountLookupSelector, +} from '@mui/x-data-grid-pro'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; + +export const isNavigationKey = (key) => + key === 'Home' || + key === 'End' || + key.indexOf('Arrow') === 0 || + key.indexOf('Page') === 0 || + key === ' '; + +const CustomGridTreeDataGroupingCell = (props) => { + const { id, field, rowNode } = props; + const apiRef = useGridApiContext(); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + + const handleKeyDown = (event) => { + if (event.key === ' ') { + event.stopPropagation(); + } + if (isNavigationKey(event.key) && !event.shiftKey) { + apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); + } + }; + + const handleClick = (event) => { + apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); + apiRef.current.setCellFocus(id, field); + event.stopPropagation(); + }; + + return ( + +
+ {filteredDescendantCount > 0 ? ( + + ) : ( + + )} +
+
+ ); +}; + +CustomGridTreeDataGroupingCell.propTypes = { + /** + * The column field of the cell that triggered the event. + */ + field: PropTypes.string.isRequired, + /** + * The grid row id. + */ + id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + /** + * The node of the row that the current cell belongs to. + */ + rowNode: PropTypes.shape({ + /** + * The id of the row children. + * @default [] + */ + children: PropTypes.arrayOf( + PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + ), + /** + * Current expansion status of the row. + * @default false + */ + childrenExpanded: PropTypes.bool, + /** + * 0-based depth of the row in the tree. + */ + depth: PropTypes.number.isRequired, + /** + * The field used to group the children of this row. + * Is `null` if no field has been used to group the children of this row. + */ + groupingField: PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.string]) + .isRequired, + /** + * The key used to group the children of this row. + */ + groupingKey: PropTypes.oneOfType([ + PropTypes.number, + PropTypes.string, + PropTypes.bool, + ]).isRequired, + /** + * The grid row id. + */ + id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + /** + * If `true`, this node has been automatically added to fill a gap in the tree structure. + * @default false + */ + isAutoGenerated: PropTypes.bool, + /** + * The row id of the parent (null if this row is a top level row). + */ + parent: PropTypes.oneOfType([ + PropTypes.oneOf([null]), + PropTypes.number, + PropTypes.string, + ]).isRequired, + }).isRequired, +}; + +const rows = [ + { + hierarchy: ['Sarah'], + jobTitle: 'Head of Human Resources', + recruitmentDate: new Date(2020, 8, 12), + id: 0, + }, + { + hierarchy: ['Thomas'], + jobTitle: 'Head of Sales', + recruitmentDate: new Date(2017, 3, 4), + id: 1, + }, + { + hierarchy: ['Thomas', 'Robert'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 11, 20), + id: 2, + }, + { + hierarchy: ['Thomas', 'Karen'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 10, 14), + id: 3, + }, + { + hierarchy: ['Thomas', 'Nancy'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2017, 10, 29), + id: 4, + }, + { + hierarchy: ['Thomas', 'Daniel'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 7, 21), + id: 5, + }, + { + hierarchy: ['Thomas', 'Christopher'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 7, 20), + id: 6, + }, + { + hierarchy: ['Thomas', 'Donald'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2019, 6, 28), + id: 7, + }, + { + hierarchy: ['Mary'], + jobTitle: 'Head of Engineering', + recruitmentDate: new Date(2016, 3, 14), + id: 8, + }, + { + hierarchy: ['Mary', 'Jennifer'], + jobTitle: 'Tech lead front', + recruitmentDate: new Date(2016, 5, 17), + id: 9, + }, + { + hierarchy: ['Mary', 'Jennifer', 'Anna'], + jobTitle: 'Front-end developer', + recruitmentDate: new Date(2019, 11, 7), + id: 10, + }, + { + hierarchy: ['Mary', 'Michael'], + jobTitle: 'Tech lead devops', + recruitmentDate: new Date(2021, 7, 1), + id: 11, + }, + { + hierarchy: ['Mary', 'Linda'], + jobTitle: 'Tech lead back', + recruitmentDate: new Date(2017, 0, 12), + id: 12, + }, + { + hierarchy: ['Mary', 'Linda', 'Elizabeth'], + jobTitle: 'Back-end developer', + recruitmentDate: new Date(2019, 2, 22), + id: 13, + }, + { + hierarchy: ['Mary', 'Linda', 'William'], + jobTitle: 'Back-end developer', + recruitmentDate: new Date(2018, 4, 19), + id: 14, + }, +]; + +const columns = [ + { + field: 'name', + headerName: 'Name', + valueGetter: (params) => { + const hierarchy = params.row.hierarchy; + return hierarchy[hierarchy.length - 1]; + }, + }, + { field: 'jobTitle', headerName: 'Job Title', width: 200 }, + { + field: 'recruitmentDate', + headerName: 'Recruitment Date', + type: 'date', + width: 150, + }, +]; + +const getTreeDataPath = (row) => row.hierarchy; + +const groupingColDef = { + headerName: 'Hierarchy', + renderCell: (params) => , +}; + +export default function TreeDataCustomGroupingColumn() { + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx new file mode 100644 index 0000000000000..480a8e7f5e1cb --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx @@ -0,0 +1,197 @@ +import * as React from 'react'; +import { + DataGridPro, + GridRenderCellParams, + useGridApiContext, + GridEvents, + GridColumns, + GridRowsProp, + DataGridProProps, + useGridSelector, + gridFilteredDescendantCountLookupSelector, +} from '@mui/x-data-grid-pro'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; + +export const isNavigationKey = (key: string) => + key === 'Home' || + key === 'End' || + key.indexOf('Arrow') === 0 || + key.indexOf('Page') === 0 || + key === ' '; + +const CustomGridTreeDataGroupingCell = (props: GridRenderCellParams) => { + const { id, field, rowNode } = props; + const apiRef = useGridApiContext(); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + + const handleKeyDown = (event) => { + if (event.key === ' ') { + event.stopPropagation(); + } + if (isNavigationKey(event.key) && !event.shiftKey) { + apiRef.current.publishEvent(GridEvents.cellNavigationKeyDown, props, event); + } + }; + + const handleClick = (event) => { + apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); + apiRef.current.setCellFocus(id, field); + event.stopPropagation(); + }; + + return ( + +
+ {filteredDescendantCount > 0 ? ( + + ) : ( + + )} +
+
+ ); +}; + +const rows: GridRowsProp = [ + { + hierarchy: ['Sarah'], + jobTitle: 'Head of Human Resources', + recruitmentDate: new Date(2020, 8, 12), + id: 0, + }, + { + hierarchy: ['Thomas'], + jobTitle: 'Head of Sales', + recruitmentDate: new Date(2017, 3, 4), + id: 1, + }, + { + hierarchy: ['Thomas', 'Robert'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 11, 20), + id: 2, + }, + { + hierarchy: ['Thomas', 'Karen'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 10, 14), + id: 3, + }, + { + hierarchy: ['Thomas', 'Nancy'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2017, 10, 29), + id: 4, + }, + { + hierarchy: ['Thomas', 'Daniel'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 7, 21), + id: 5, + }, + { + hierarchy: ['Thomas', 'Christopher'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2020, 7, 20), + id: 6, + }, + { + hierarchy: ['Thomas', 'Donald'], + jobTitle: 'Sales Person', + recruitmentDate: new Date(2019, 6, 28), + id: 7, + }, + { + hierarchy: ['Mary'], + jobTitle: 'Head of Engineering', + recruitmentDate: new Date(2016, 3, 14), + id: 8, + }, + { + hierarchy: ['Mary', 'Jennifer'], + jobTitle: 'Tech lead front', + recruitmentDate: new Date(2016, 5, 17), + id: 9, + }, + { + hierarchy: ['Mary', 'Jennifer', 'Anna'], + jobTitle: 'Front-end developer', + recruitmentDate: new Date(2019, 11, 7), + id: 10, + }, + { + hierarchy: ['Mary', 'Michael'], + jobTitle: 'Tech lead devops', + recruitmentDate: new Date(2021, 7, 1), + id: 11, + }, + { + hierarchy: ['Mary', 'Linda'], + jobTitle: 'Tech lead back', + recruitmentDate: new Date(2017, 0, 12), + id: 12, + }, + { + hierarchy: ['Mary', 'Linda', 'Elizabeth'], + jobTitle: 'Back-end developer', + recruitmentDate: new Date(2019, 2, 22), + id: 13, + }, + { + hierarchy: ['Mary', 'Linda', 'William'], + jobTitle: 'Back-end developer', + recruitmentDate: new Date(2018, 4, 19), + id: 14, + }, +]; + +const columns: GridColumns = [ + { + field: 'name', + headerName: 'Name', + valueGetter: (params) => { + const hierarchy = params.row.hierarchy as string[]; + return hierarchy[hierarchy.length - 1]; + }, + }, + { field: 'jobTitle', headerName: 'Job Title', width: 200 }, + { + field: 'recruitmentDate', + headerName: 'Recruitment Date', + type: 'date', + width: 150, + }, +]; + +const getTreeDataPath = (row) => row.hierarchy; + +const groupingColDef: DataGridProProps['groupingColDef'] = { + headerName: 'Hierarchy', + renderCell: (params) => , +}; + +export default function TreeDataCustomGroupingColumn() { + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview new file mode 100644 index 0000000000000..26cb070f5f6d4 --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 3db2e177955d9..fa3a7bdae8102 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -10,6 +10,8 @@ title: Data Grid - Group & Pivot Use row grouping to group the rows according to one or several columns value. +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} + > ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. > > To avoid future regression for users of the Pro plan, the feature needs to be explicitly activated using the `rowGrouping` experimental feature flag. @@ -34,6 +36,9 @@ initialState={{ }} ``` +The basic parameters are the columns you want to check for repeating values. +In this example, we want to group all the movies matching the same company name, followed by a second group matching the director's name. + {{"demo": "pages/components/data-grid/group-pivot/RowGroupingInitialState.js", "bg": "inline", "defaultCodeOpen": false}} #### Controlled row grouping @@ -74,7 +79,7 @@ The callback is called for each grouping column, and it receives the respective #### Show values for the leaves -By default, the grouped rows display no value on their grouping columns' cells. We're calling those cells "leaves". +By default, the grouped rows display no value on their grouping columns' cells. We're calling those cells "leaves". If you want to display some value, you can provide a `leafField` property to the `groupingColDef`. @@ -243,7 +248,9 @@ const rows: GridRowsProp = [ ### Custom grouping column -Same behavior as for the [Row grouping](##grouping-column-customization) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. +Same behavior as for the [Row grouping](#grouping-columns) except for the `leafField` and `mainGroupingCriteria` which are not applicable for the Tree Data. + +{{"demo": "pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.js", "bg": "inline", "defaultCodeOpen": false}} #### Accessing the grouping column field diff --git a/packages/grid/x-data-grid-generator/src/useMovieData.ts b/packages/grid/x-data-grid-generator/src/useMovieData.ts index e52014db1ffd2..9dbcf0ae44b91 100644 --- a/packages/grid/x-data-grid-generator/src/useMovieData.ts +++ b/packages/grid/x-data-grid-generator/src/useMovieData.ts @@ -1,6 +1,7 @@ import { GridColumns, DataGridProps, GridRowModel } from '@mui/x-data-grid'; type Movie = { + id: number; title: string; gross: number; director: string; @@ -48,6 +49,7 @@ const COLUMNS: GridColumns = [ const ROWS: GridRowModel[] = [ { + id: 0, title: 'Avatar', gross: 2847246203, director: 'James Cameron', @@ -58,6 +60,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 1, title: 'Avengers: Endgame', gross: 2797501328, director: 'Anthony & Joe Russo', @@ -69,6 +72,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 2, title: 'Titanic', gross: 2187425379, director: 'James Cameron', @@ -79,6 +83,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 3, title: 'Star Wars: The Force Awakens', gross: 2068223624, director: 'J. J. Abrams', @@ -90,6 +95,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 4, title: 'Avengers: Infinity War', gross: 2048359754, director: 'Anthony & Joe Russo', @@ -101,6 +107,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 5, title: 'Jurassic World', gross: 1671713208, director: 'Colin Trevorrow', @@ -112,6 +119,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 6, title: 'The Lion King', gross: 1656943394, director: 'Jon Favreau', @@ -122,6 +130,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 7, title: 'The Avengers', gross: 1518812988, director: 'Joss Whedon', @@ -133,6 +142,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 8, title: 'Furious 7', gross: 1516045911, director: 'James Wan', @@ -144,6 +154,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 9, title: 'Frozen II', gross: 1450026933, director: 'Chris Buck & Jennifer Lee', @@ -155,6 +166,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 10, title: 'Avengers: Age of Ultron', gross: 1402804868, director: 'Joss Whedon', @@ -166,6 +178,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 11, title: 'Black Panther', gross: 1347280838, director: 'Ryan Coogler', @@ -177,6 +190,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 12, title: 'Harry Potter and the Deathly Hallows – Part 2', gross: 1342025430, director: 'David Yates', @@ -187,6 +201,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 13, title: 'Star Wars: The Last Jedi', gross: 1332539889, director: 'Rian Johnson', @@ -198,6 +213,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 14, title: 'Jurassic World: Fallen Kingdom', gross: 1309484461, director: 'J. A. Bayona', @@ -209,6 +225,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 15, title: 'Frozen', gross: 1290000000, director: 'Chris Buck & Jennifer Lee', @@ -220,6 +237,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 16, title: 'Beauty and the Beast', gross: 1263521136, director: 'Bill Condon', @@ -230,6 +248,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 17, title: 'Incredibles 2', gross: 1242805359, director: 'Brad Bird', @@ -240,6 +259,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 18, title: 'The Fate of the Furious', gross: 1238764765, director: 'F. Gary Gray', @@ -251,6 +271,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 19, title: 'Iron Man 3', gross: 1214811252, director: 'Shane Black', @@ -262,6 +283,7 @@ const ROWS: GridRowModel[] = [ }, }, { + id: 20, title: 'Minions', gross: 11159398397, director: 'Pierre Coffin & Kyle Balda', @@ -273,11 +295,8 @@ const ROWS: GridRowModel[] = [ }, ]; -const getRowId = (row: any) => row.title; - -export const useMovieData = (): Pick => { +export const useMovieData = (): Pick => { return { - getRowId, rows: ROWS, columns: COLUMNS, }; From 7c98de8489251c07e206c2f4d737647fb5130624 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 14 Jan 2022 11:00:02 +0100 Subject: [PATCH 26/33] Fix --- .../api-docs/data-grid/data-grid-pro.json | 4 ++-- docs/pages/api-docs/data-grid/data-grid.json | 4 ++-- .../tests/rowGrouping.DataGridPro.test.tsx | 19 ------------------- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/docs/pages/api-docs/data-grid/data-grid-pro.json b/docs/pages/api-docs/data-grid/data-grid-pro.json index 703b821cea18a..92bb747ba8b32 100644 --- a/docs/pages/api-docs/data-grid/data-grid-pro.json +++ b/docs/pages/api-docs/data-grid/data-grid-pro.json @@ -247,7 +247,7 @@ "type": { "name": "elementType" } }, "GroupingCriteriaExpandIcon": { - "default": "KeyboardArrowRight", + "default": "GridKeyboardArrowRight", "type": { "name": "elementType" } }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, @@ -262,7 +262,7 @@ "Row": { "type": { "name": "elementType" } }, "Toolbar": { "default": "null", "type": { "name": "elementType | null" } }, "TreeDataCollapseIcon": { "default": "GridExpandMoreIcon", "type": { "name": "elementType" } }, - "TreeDataExpandIcon": { "default": "KeyboardArrowRight", "type": { "name": "elementType" } } + "TreeDataExpandIcon": { "default": "GridKeyboardArrowRight", "type": { "name": "elementType" } } }, "name": "DataGridPro", "styles": { diff --git a/docs/pages/api-docs/data-grid/data-grid.json b/docs/pages/api-docs/data-grid/data-grid.json index 17ff11895ae6f..17b7cd5ad5044 100644 --- a/docs/pages/api-docs/data-grid/data-grid.json +++ b/docs/pages/api-docs/data-grid/data-grid.json @@ -194,7 +194,7 @@ "type": { "name": "elementType" } }, "GroupingCriteriaExpandIcon": { - "default": "KeyboardArrowRight", + "default": "GridKeyboardArrowRight", "type": { "name": "elementType" } }, "Header": { "default": "GridHeader", "type": { "name": "elementType" } }, @@ -209,7 +209,7 @@ "Row": { "type": { "name": "elementType" } }, "Toolbar": { "default": "null", "type": { "name": "elementType | null" } }, "TreeDataCollapseIcon": { "default": "GridExpandMoreIcon", "type": { "name": "elementType" } }, - "TreeDataExpandIcon": { "default": "KeyboardArrowRight", "type": { "name": "elementType" } } + "TreeDataExpandIcon": { "default": "GridKeyboardArrowRight", "type": { "name": "elementType" } } }, "name": "DataGrid", "styles": { diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index 7e081f27e4cbe..ec1ef04029545 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -612,25 +612,6 @@ describe(' - Group Rows By Column', () => { ]); }); - it('should react to defaultGroupingExpansionDepth updates', () => { - const { setProps } = render( - , - ); - expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', 'Cat B (2)']); - setProps({ defaultGroupingExpansionDepth: 1 }); - expect(getColumnValues(0)).to.deep.equal([ - 'Cat A (3)', - 'Cat 1 (1)', - 'Cat 2 (2)', - 'Cat B (2)', - 'Cat 2 (1)', - 'Cat 1 (1)', - ]); - }); - it('should not re-apply default expansion on rerender after expansion manually toggled', () => { const { setProps } = render( , From 3662e83b6cab0f8c623162525687eca0ae51f1b5 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 14 Jan 2022 11:16:30 +0100 Subject: [PATCH 27/33] Work --- .../TreeDataCustomGroupingColumn.tsx.preview | 10 +++++----- .../_modules_/grid/utils/tree/buildRowTree.test.ts | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview index 26cb070f5f6d4..35b9b522e32e6 100644 --- a/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/TreeDataCustomGroupingColumn.tsx.preview @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts index 8844770f2b5c8..666b5a93d4dab 100644 --- a/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts +++ b/packages/grid/_modules_/grid/utils/tree/buildRowTree.test.ts @@ -308,6 +308,7 @@ describe('buildRowTree', () => { }, ], defaultGroupingExpansionDepth: -1, + previousTree: null, }); // The tree structure: @@ -319,7 +320,7 @@ describe('buildRowTree', () => { expect(response.tree).to.deep.equal({ '0': { id: 0, - childrenExpanded: false, + childrenExpanded: undefined, isAutoGenerated: false, parent: 'auto-generated-row-field1/value-1-1-field2/value-2-1', groupingKey: 'value-leaf-1', @@ -329,7 +330,7 @@ describe('buildRowTree', () => { }, '1': { id: 1, - childrenExpanded: false, + childrenExpanded: undefined, isAutoGenerated: false, parent: 'auto-generated-row-field2/value-2-1', groupingKey: 'value-leaf-1', From fa64fb4439e5d5982197a12d8f0a2c382256eaa4 Mon Sep 17 00:00:00 2001 From: delangle Date: Fri, 14 Jan 2022 15:53:33 +0100 Subject: [PATCH 28/33] Work --- docs/pages/api-docs/data-grid/grid-col-def.md | 2 +- packages/grid/_modules_/grid/models/colDef/gridColDef.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/pages/api-docs/data-grid/grid-col-def.md b/docs/pages/api-docs/data-grid/grid-col-def.md index cac75f84a110c..f14836ab13227 100644 --- a/docs/pages/api-docs/data-grid/grid-col-def.md +++ b/docs/pages/api-docs/data-grid/grid-col-def.md @@ -32,7 +32,7 @@ import { GridColDef } from '@mui/x-data-grid'; | hide? | boolean | false | If `true`, hide the column. | | hideable? | boolean | true | If `false`, removes the buttons for hiding this column. | | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | -| keyGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transform a complex cell value into a key that be used for grouping the rows. | +| keyGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | minWidth? | number | 50 | Sets the minimum width of a column. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | diff --git a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts index 01f7dfb038691..3307261776da9 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts @@ -128,7 +128,7 @@ export interface GridColDef { */ valueGetter?: (params: GridValueGetterParams) => GridCellValue; /** - * Function that transform a complex cell value into a key that be used for grouping the rows. + * Function that transforms a complex cell value into a key that be used for grouping the rows. * @param {GridKeyGetterParams} params Object containing parameters for the getter. * @returns {GridKeyValue | null | undefined} The cell key. */ From 837260e0e73ff390ac3b860c09e18dc5a5c40255 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 18 Jan 2022 09:37:32 +0100 Subject: [PATCH 29/33] =?UTF-8?q?Code=20review:=20Jos=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/pages/api-docs/data-grid/grid-col-def.md | 2 +- ...r.js => RowGroupingGroupingValueGetter.js} | 13 ++- ...tsx => RowGroupingGroupingValueGetter.tsx} | 20 +++- ...owGroupingGroupingValueGetter.tsx.preview} | 0 .../RowGroupingKeyGetterValueGetter.js | 89 --------------- .../RowGroupingKeyGetterValueGetter.tsx | 106 ------------------ ...owGroupingKeyGetterValueGetter.tsx.preview | 13 --- .../data-grid/group-pivot/group-pivot.md | 15 +-- .../rowGrouping/useGridRowGrouping.tsx | 25 ++--- .../hooks/features/rows/useGridParamsApi.ts | 4 +- .../grid/models/colDef/gridColDef.ts | 6 +- .../grid/models/params/gridCellParams.ts | 39 +++---- .../src/commodities.columns.tsx | 2 +- .../tests/rowGrouping.DataGridPro.test.tsx | 42 +++---- 14 files changed, 76 insertions(+), 300 deletions(-) rename docs/src/pages/components/data-grid/group-pivot/{RowGroupingKeyGetter.js => RowGroupingGroupingValueGetter.js} (80%) rename docs/src/pages/components/data-grid/group-pivot/{RowGroupingKeyGetter.tsx => RowGroupingGroupingValueGetter.tsx} (76%) rename docs/src/pages/components/data-grid/group-pivot/{RowGroupingKeyGetter.tsx.preview => RowGroupingGroupingValueGetter.tsx.preview} (100%) delete mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js delete mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx delete mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview diff --git a/docs/pages/api-docs/data-grid/grid-col-def.md b/docs/pages/api-docs/data-grid/grid-col-def.md index f14836ab13227..3b278b4083388 100644 --- a/docs/pages/api-docs/data-grid/grid-col-def.md +++ b/docs/pages/api-docs/data-grid/grid-col-def.md @@ -32,7 +32,7 @@ import { GridColDef } from '@mui/x-data-grid'; | hide? | boolean | false | If `true`, hide the column. | | hideable? | boolean | true | If `false`, removes the buttons for hiding this column. | | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | -| keyGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | +| groupingValueGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | minWidth? | number | 50 | Sets the minimum width of a column. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.js similarity index 80% rename from docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.js index 7e14b635d1a40..98c2ea6044117 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; -const INITIAL_GROUPING_COLUMN_MODEL = ['composer']; +const INITIAL_GROUPING_COLUMN_MODEL = ['composer', 'decade']; const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { const prevModel = React.useRef(initialModel); @@ -34,7 +34,7 @@ const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) ); }; -export default function RowGroupingKeyGetter() { +export default function RowGroupingGroupingValueGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -45,9 +45,16 @@ export default function RowGroupingKeyGetter() { field: 'composer', headerName: 'Composer', renderCell: (params) => params.value?.name, - keyGetter: (params) => params.value.name, + groupingValueGetter: (params) => params.value.name, width: 200, }, + { + field: 'decade', + headerName: 'Decade', + valueGetter: (params) => Math.floor(params.row.year / 10) * 10, + groupingValueGetter: (params) => Math.floor(params.row.year / 10) * 10, + renderCell: (params) => `${params.value.toString().slice(-2)}'s`, + }, ], [data.columns], ); diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.tsx similarity index 76% rename from docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.tsx index 483d91569cbda..8cc0e1f76eb4e 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.tsx @@ -5,13 +5,13 @@ import { GridColumns, GridEvents, GridRowGroupingModel, - GridKeyGetterParams, + GridGroupingValueGetterParams, GridRenderCellParams, useGridApiRef, } from '@mui/x-data-grid-pro'; import { useMovieData } from '@mui/x-data-grid-generator'; -const INITIAL_GROUPING_COLUMN_MODEL = ['composer']; +const INITIAL_GROUPING_COLUMN_MODEL = ['composer', 'decade']; const useKeepGroupingColumnsHidden = ( apiRef: GridApiRef, @@ -47,7 +47,7 @@ const useKeepGroupingColumnsHidden = ( ); }; -export default function RowGroupingKeyGetter() { +export default function RowGroupingGroupingValueGetter() { const data = useMovieData(); const apiRef = useGridApiRef(); @@ -59,10 +59,20 @@ export default function RowGroupingKeyGetter() { headerName: 'Composer', renderCell: (params: GridRenderCellParams<{ name: string } | undefined>) => params.value?.name, - keyGetter: (params: GridKeyGetterParams<{ name: string }>) => - params.value.name, + groupingValueGetter: ( + params: GridGroupingValueGetterParams<{ name: string }>, + ) => params.value.name, width: 200, }, + { + field: 'decade', + headerName: 'Decade', + valueGetter: (params): number => Math.floor(params.row.year / 10) * 10, + groupingValueGetter: (params): number => + Math.floor(params.row.year / 10) * 10, + renderCell: (params: GridRenderCellParams) => + `${params.value.toString().slice(-2)}'s`, + }, ], [data.columns], ); diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.tsx.preview similarity index 100% rename from docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetter.tsx.preview rename to docs/src/pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.tsx.preview diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js deleted file mode 100644 index 5f76a9acc4924..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js +++ /dev/null @@ -1,89 +0,0 @@ -import * as React from 'react'; -import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; -import { useMovieData } from '@mui/x-data-grid-generator'; - -const INITIAL_GROUPING_COLUMN_MODEL = ['decade']; - -const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - - prevModel.current = initialModel; - }); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - -export default function RowGroupingKeyGetterValueGetter() { - const data = useMovieData(); - const apiRef = useGridApiRef(); - - const columnsWithDecade = React.useMemo( - () => [ - ...data.columns, - { - field: 'decade', - headerName: 'Decade', - valueGetter: (params) => { - const value = Math.floor(params.row.year / 10) * 10; - - if (params.row.year == null) { - return null; - } - - return { - value, - name: `${value.toString().slice(-2)}'s`, - }; - }, - keyGetter: (params) => params.value?.value, - renderCell: (params) => params.value?.name, - }, - ], - [data.columns], - ); - - const columns = useKeepGroupingColumnsHidden( - apiRef, - columnsWithDecade, - INITIAL_GROUPING_COLUMN_MODEL, - ); - - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx deleted file mode 100644 index 0be48ac2fe2c6..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import * as React from 'react'; -import { - DataGridPro, - GridApiRef, - GridColumns, - GridEvents, - GridRowGroupingModel, - GridKeyGetterParams, - GridRenderCellParams, - useGridApiRef, -} from '@mui/x-data-grid-pro'; -import { useMovieData } from '@mui/x-data-grid-generator'; - -type Decade = { value: number; name: string }; - -const INITIAL_GROUPING_COLUMN_MODEL = ['decade']; - -const useKeepGroupingColumnsHidden = ( - apiRef: GridApiRef, - columns: GridColumns, - initialModel: GridRowGroupingModel, - leafField?: string, -) => { - const prevModel = React.useRef(initialModel); - - React.useEffect(() => { - apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { - apiRef.current.updateColumns([ - ...newModel - .filter((field) => !prevModel.current.includes(field)) - .map((field) => ({ field, hide: true })), - ...prevModel.current - .filter((field) => !newModel.includes(field)) - .map((field) => ({ field, hide: false })), - ]); - prevModel.current = initialModel; - }); - }, [apiRef, initialModel]); - - return React.useMemo( - () => - columns.map((colDef) => - initialModel.includes(colDef.field) || - (leafField && colDef.field === leafField) - ? { ...colDef, hide: true } - : colDef, - ), - [columns, initialModel, leafField], - ); -}; - -export default function RowGroupingKeyGetterValueGetter() { - const data = useMovieData(); - const apiRef = useGridApiRef(); - - const columnsWithDecade = React.useMemo( - () => [ - ...data.columns, - { - field: 'decade', - headerName: 'Decade', - valueGetter: (params): Decade | null => { - const value = Math.floor(params.row.year / 10) * 10; - - if (params.row.year == null) { - return null; - } - - return { - value, - name: `${value.toString().slice(-2)}'s`, - }; - }, - keyGetter: (params: GridKeyGetterParams) => - params.value?.value, - renderCell: (params: GridRenderCellParams) => - params.value?.name, - }, - ], - [data.columns], - ); - - const columns = useKeepGroupingColumnsHidden( - apiRef, - columnsWithDecade, - INITIAL_GROUPING_COLUMN_MODEL, - ); - - return ( -
- -
- ); -} diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview deleted file mode 100644 index d99ba502224bd..0000000000000 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.tsx.preview +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index fa3a7bdae8102..43cb1bd43e7b1 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -108,27 +108,24 @@ In the example below, the `director` column can not be grouped. And in all examp {{"demo": "pages/components/data-grid/group-pivot/RowGroupingColDefCanBeGrouped.js", "bg": "inline", "defaultCodeOpen": false}} -### Using 'keyGetter' for complex grouping value +### Using `groupingValueGetter` for complex grouping value -In most scenarios, to handle complex values (e.g. nested structures), a `valueGetter` property must be provided to the column definition to convert it into a simple value. -But sometimes, you may want to keep the value in its raw format, to be used in a custom cell renderer, and thus using a value getter is not possible. -In this case, pass a `keyGetter` property to the column definition to convert this object into a serializable value. +The grouping value has to be either a `string`, a `number`, `null` or `undefined`. +If your cell value is more complex, pass a `groupingValueGetter` property to the column definition to convert it into a valid value. ```ts const columns: GridColumns = [ { field: 'composer', - keyGetter: (params) => params.value.name, + groupingValueGetter: (params) => params.value.name, }, // ... ]; ``` -{{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetter.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingGroupingValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} -**Note**: If your column also have a `valueGetter` property, its value is used as the parameter for the `keyGetter` method. - -{{"demo": "pages/components/data-grid/group-pivot/RowGroupingKeyGetterValueGetter.js", "bg": "inline", "defaultCodeOpen": false}} +**Note**: If your column also have a `valueGetter` property, the value passed to the `groupingValueGetter` method will still be the row value from the `row[field]`. ### Rows with missing groups diff --git a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx index c5d06fa64fe78..d33343953475f 100644 --- a/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx +++ b/packages/grid/_modules_/grid/hooks/features/rowGrouping/useGridRowGrouping.tsx @@ -6,8 +6,7 @@ import type { GridRowId, GridColDef, GridKeyValue, - GridCellValue, - GridValueGetterSimpleParams, + GridGroupingValueGetterParams, GridStateColDef, } from '../../../models'; import { GridEvents, GridEventListener } from '../../../models/events'; @@ -115,11 +114,12 @@ export const useGridRowGrouping = ( id: GridRowId; colDef: GridColDef; }) => { - let value: GridCellValue; - if (colDef.valueGetter) { - const valueGetterParams: GridValueGetterSimpleParams = { + let key: GridKeyValue | null | undefined; + if (colDef.groupingValueGetter) { + const groupingValueGetterParams: GridGroupingValueGetterParams = { colDef, field: colDef.field, + value: row[colDef.field], id, row, rowNode: { @@ -127,20 +127,9 @@ export const useGridRowGrouping = ( id, }, }; - value = colDef.valueGetter(valueGetterParams); - } else { - value = row[colDef.field]; - } - - let key: GridKeyValue | null | undefined; - if (colDef.keyGetter) { - key = colDef.keyGetter({ - value, - id, - field: colDef.field, - }); + key = colDef.groupingValueGetter(groupingValueGetterParams); } else { - key = value as GridKeyValue; + key = row[colDef.field] as GridKeyValue | null | undefined; } return { diff --git a/packages/grid/_modules_/grid/hooks/features/rows/useGridParamsApi.ts b/packages/grid/_modules_/grid/hooks/features/rows/useGridParamsApi.ts index b7705bf484dc5..f0682311f6805 100644 --- a/packages/grid/_modules_/grid/hooks/features/rows/useGridParamsApi.ts +++ b/packages/grid/_modules_/grid/hooks/features/rows/useGridParamsApi.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { GridApiRef } from '../../../models/api/gridApiRef'; import { GridParamsApi } from '../../../models/api/gridParamsApi'; import { GridRowId } from '../../../models/gridRows'; -import { GridCellParams, GridValueGetterFullParams } from '../../../models/params/gridCellParams'; +import { GridCellParams, GridValueGetterParams } from '../../../models/params/gridCellParams'; import { GridColumnHeaderParams } from '../../../models/params/gridColumnHeaderParams'; import { GridRowParams } from '../../../models/params/gridRowParams'; import { @@ -100,7 +100,7 @@ export function useGridParamsApi(apiRef: GridApiRef) { const cellFocus = gridFocusCellSelector(apiRef.current.state); const cellTabIndex = gridTabIndexCellSelector(apiRef.current.state); - const params: GridValueGetterFullParams = { + const params: GridValueGetterParams = { id, field, row, diff --git a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts index 3307261776da9..fd268bffc2581 100644 --- a/packages/grid/_modules_/grid/models/colDef/gridColDef.ts +++ b/packages/grid/_modules_/grid/models/colDef/gridColDef.ts @@ -5,7 +5,7 @@ import { GridColumnHeaderClassNamePropType } from '../gridColumnHeaderClass'; import { GridFilterOperator } from '../gridFilterOperator'; import { GridCellParams, - GridKeyGetterParams, + GridGroupingValueGetterParams, GridRenderCellParams, GridRenderEditCellParams, GridValueFormatterParams, @@ -129,10 +129,10 @@ export interface GridColDef { valueGetter?: (params: GridValueGetterParams) => GridCellValue; /** * Function that transforms a complex cell value into a key that be used for grouping the rows. - * @param {GridKeyGetterParams} params Object containing parameters for the getter. + * @param {GridGroupingValueGetterParams} params Object containing parameters for the getter. * @returns {GridKeyValue | null | undefined} The cell key. */ - keyGetter?: (params: GridKeyGetterParams) => GridKeyValue | null | undefined; + groupingValueGetter?: (params: GridGroupingValueGetterParams) => GridKeyValue | null | undefined; /** * Function that allows to customize how the entered value is stored in the row. * It only works with cell/row editing. diff --git a/packages/grid/_modules_/grid/models/params/gridCellParams.ts b/packages/grid/_modules_/grid/models/params/gridCellParams.ts index 6fe663efda73d..d6ad6b72a370c 100644 --- a/packages/grid/_modules_/grid/models/params/gridCellParams.ts +++ b/packages/grid/_modules_/grid/models/params/gridCellParams.ts @@ -83,9 +83,9 @@ export interface GridRenderEditCellParams extends GridEditCellProps { } /** - * Parameters passed when calling `colDef.valueGetter` in the rendering sequence. + * Parameters passed to `colDef.valueGetter`. */ -export interface GridValueGetterFullParams +export interface GridValueGetterParams extends Omit, 'formattedValue' | 'isEditable'> { /** * GridApi that let you manipulate the grid. @@ -94,9 +94,14 @@ export interface GridValueGetterFullParams } /** - * Parameters passed when calling `colDef.valueGetter` in the row grouping sequence. + * @deprecated Use `GridValueGetterParams` instead. */ -export interface GridValueGetterSimpleParams { +export type GridValueGetterFullParams = GridValueGetterParams; + +/** + * Parameters passed to `colDef.groupingValueGetter`. + */ +export interface GridGroupingValueGetterParams { /** * The grid row id. */ @@ -105,6 +110,10 @@ export interface GridValueGetterSimpleParams { * The column field of the cell that triggered the event. */ field: string; + /** + * The cell value, does not take `valueGetter` into account. + */ + value: V; /** * The row model of the row that the current cell belongs to. */ @@ -120,10 +129,6 @@ export interface GridValueGetterSimpleParams { rowNode: Pick; } -export type GridValueGetterParams = - | GridValueGetterFullParams - | GridValueGetterSimpleParams; - /** * Object passed as parameter in the column [[GridColDef]] value setter callback. */ @@ -178,21 +183,3 @@ export interface GridPreProcessEditCellProps { */ props: GridEditCellProps; } - -/** - * Object passed as parameter in the column [[GridColDef]] key getter callback. - */ -export interface GridKeyGetterParams { - /** - * The grid row id. - */ - id: GridRowId; - /** - * The column field of the cell that triggered the event. - */ - field: string; - /** - * The cell value (if the column has valueGetter, this is the value returned by it). - */ - value: V; -} diff --git a/packages/grid/x-data-grid-generator/src/commodities.columns.tsx b/packages/grid/x-data-grid-generator/src/commodities.columns.tsx index ffc5d67825e80..15c0d6f2cff64 100644 --- a/packages/grid/x-data-grid-generator/src/commodities.columns.tsx +++ b/packages/grid/x-data-grid-generator/src/commodities.columns.tsx @@ -242,7 +242,7 @@ export const getCommodityColumns = (editable = false): GridColDefGenerator[] => return value; }, - keyGetter: (params) => params.value.code, + groupingValueGetter: (params) => params.value.code, type: 'singleSelect', valueOptions: COUNTRY_ISO_OPTIONS, editable, diff --git a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx index ec1ef04029545..36e0dc01bc61c 100644 --- a/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/rowGrouping.DataGridPro.test.tsx @@ -12,7 +12,7 @@ import { getRowGroupingFieldFromGroupingCriteria, GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD, GridApiRef, - GridKeyGetterParams, + GridGroupingValueGetterParams, GridPreferencePanelsValue, GridRowsProp, GridRowTreeNodeConfig, @@ -1335,8 +1335,8 @@ describe(' - Group Rows By Column', () => { }); }); - describe('colDef: keyGetter & valueGetter', () => { - it('should use keyGetter to group rows when defined', () => { + describe('colDef: groupingValueGetter & valueGetter', () => { + it('should use groupingValueGetter to group rows when defined', () => { render( - Group Rows By Column', () => { }, { field: 'category1', - keyGetter: (params: GridKeyGetterParams) => `key ${params.value}`, + groupingValueGetter: (params: GridGroupingValueGetterParams) => + `groupingValue ${params.value}`, }, ]} initialState={{ rowGrouping: { model: ['category1'] } }} @@ -1353,18 +1354,18 @@ describe(' - Group Rows By Column', () => { />, ); expect(getColumnValues(0)).to.deep.equal([ - 'key Cat A (3)', + 'groupingValue Cat A (3)', '', '', '', - 'key Cat B (2)', + 'groupingValue Cat B (2)', '', '', ]); expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '3', '4']); }); - it('should use valueGetter to group the rows when defined', () => { + it('should not use valueGetter to group the rows when defined', () => { render( - Group Rows By Column', () => { field: 'id', }, { - field: 'complexCategory1', + field: 'category1', valueGetter: (params) => `value ${params.row.category1}`, }, ]} - initialState={{ rowGrouping: { model: ['complexCategory1'] } }} + initialState={{ rowGrouping: { model: ['category1'] } }} defaultGroupingExpansionDepth={-1} />, ); - expect(getColumnValues(0)).to.deep.equal([ - 'value Cat A (3)', - '', - '', - '', - 'value Cat B (2)', - '', - '', - ]); + expect(getColumnValues(0)).to.deep.equal(['Cat A (3)', '', '', '', 'Cat B (2)', '', '']); expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '3', '4']); }); - it('should pass the return value of valueGetter to the keyGetter callback when both defined', () => { + it('should still pass the raw row value to the groupingValueGetter callback when valueGetter defined', () => { render( `value ${params.row.category1}`, - keyGetter: (params: GridKeyGetterParams) => `key ${params.value}`, + groupingValueGetter: (params: GridGroupingValueGetterParams) => + `groupingValue ${params.row.category1}`, }, ]} defaultGroupingExpansionDepth={-1} />, ); expect(getColumnValues(0)).to.deep.equal([ - 'key value Cat A (3)', + 'groupingValue Cat A (3)', '', '', '', - 'key value Cat B (2)', + 'groupingValue Cat B (2)', '', '', ]); From 408af80394f6c7fe100258ad016e94e9e08d992a Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 18 Jan 2022 09:38:42 +0100 Subject: [PATCH 30/33] =?UTF-8?q?Code=20review:=20Jos=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/src/pages/components/data-grid/group-pivot/group-pivot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index 43cb1bd43e7b1..d75735ef56fde 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -8,7 +8,7 @@ title: Data Grid - Group & Pivot ## Row grouping [](https://mui.com/store/items/material-ui-pro/) -Use row grouping to group the rows according to one or several columns value. +For when you need to group rows based on repeated column values, and/or custom functions. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} From 11f77c9eba1724f74481e8b9d73e2abe1e2ba813 Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 18 Jan 2022 10:11:13 +0100 Subject: [PATCH 31/33] Work --- docs/pages/api-docs/data-grid/grid-col-def.md | 2 +- scripts/x-data-grid-pro.exports.json | 7 +++---- scripts/x-data-grid.exports.json | 7 +++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/pages/api-docs/data-grid/grid-col-def.md b/docs/pages/api-docs/data-grid/grid-col-def.md index 3b278b4083388..714ab227b56c8 100644 --- a/docs/pages/api-docs/data-grid/grid-col-def.md +++ b/docs/pages/api-docs/data-grid/grid-col-def.md @@ -26,13 +26,13 @@ import { GridColDef } from '@mui/x-data-grid'; | filterOperators? | GridFilterOperator[] | | Allows setting the filter operators for this column. | | flex? | number | | If set, it indicates that a column has fluid width. Range [0, ∞). | | groupable? | boolean | true | If `true`, the rows can be grouped based on this column values (pro-plan only). | +| groupingValueGetter? | (params: GridGroupingValueGetterParams) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | headerAlign? | GridAlignment | | Header cell element alignment. | | headerClassName? | GridColumnHeaderClassNamePropType | | Class name that will be added in the column header cell. | | headerName? | string | | The title of the column rendered in the column header cell. | | hide? | boolean | false | If `true`, hide the column. | | hideable? | boolean | true | If `false`, removes the buttons for hiding this column. | | hideSortIcons? | boolean | false | Toggle the visibility of the sort icons. | -| groupingValueGetter? | (params: GridKeyGetterParams) => GridKeyValue \| null \| undefined | | Function that transforms a complex cell value into a key that be used for grouping the rows. | | minWidth? | number | 50 | Sets the minimum width of a column. | | pinnable? | boolean | true | If `false`, the menu items for column pinning menu will not be rendered.
Only available in DataGridPro. | | preProcessEditCellProps? | (params: GridPreProcessEditCellProps) => GridEditCellProps \| Promise<GridEditCellProps> | | Callback fired when the edit props of the cell changes.
It allows to process the props that saved into the state. | diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index b6cedd341acad..a3fcce5c2021e 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -213,6 +213,7 @@ { "name": "GridFooterPlaceholder", "kind": "Function" }, { "name": "GridGroupingColDefOverride", "kind": "Interface" }, { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, + { "name": "GridGroupingValueGetterParams", "kind": "Interface" }, { "name": "GridHeader", "kind": "Variable" }, { "name": "GridHeaderCheckbox", "kind": "ExportSpecifier" }, { "name": "GridHeaderPlaceholder", "kind": "Function" }, @@ -221,7 +222,6 @@ { "name": "GridInitialState", "kind": "Interface" }, { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, { "name": "GridKeyboardArrowRight", "kind": "Variable" }, - { "name": "GridKeyGetterParams", "kind": "Interface" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, @@ -367,9 +367,8 @@ { "name": "GridTypeFilterInputValueProps", "kind": "Interface" }, { "name": "GridUpdateAction", "kind": "TypeAlias" }, { "name": "GridValueFormatterParams", "kind": "Interface" }, - { "name": "GridValueGetterFullParams", "kind": "Interface" }, - { "name": "GridValueGetterParams", "kind": "TypeAlias" }, - { "name": "GridValueGetterSimpleParams", "kind": "Interface" }, + { "name": "GridValueGetterFullParams", "kind": "TypeAlias" }, + { "name": "GridValueGetterParams", "kind": "Interface" }, { "name": "GridValueOptionsParams", "kind": "Interface" }, { "name": "GridValueSetterParams", "kind": "Interface" }, { "name": "GridViewHeadlineIcon", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 920f3a2a84843..eb9c706eda163 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -213,6 +213,7 @@ { "name": "GridFooterPlaceholder", "kind": "Function" }, { "name": "GridGroupingColDefOverride", "kind": "Interface" }, { "name": "GridGroupingColDefOverrideParams", "kind": "Interface" }, + { "name": "GridGroupingValueGetterParams", "kind": "Interface" }, { "name": "GridHeader", "kind": "Variable" }, { "name": "GridHeaderCheckbox", "kind": "ExportSpecifier" }, { "name": "GridHeaderPlaceholder", "kind": "Function" }, @@ -221,7 +222,6 @@ { "name": "GridInitialState", "kind": "Interface" }, { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, { "name": "GridKeyboardArrowRight", "kind": "Variable" }, - { "name": "GridKeyGetterParams", "kind": "Interface" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, @@ -367,9 +367,8 @@ { "name": "GridTypeFilterInputValueProps", "kind": "Interface" }, { "name": "GridUpdateAction", "kind": "TypeAlias" }, { "name": "GridValueFormatterParams", "kind": "Interface" }, - { "name": "GridValueGetterFullParams", "kind": "Interface" }, - { "name": "GridValueGetterParams", "kind": "TypeAlias" }, - { "name": "GridValueGetterSimpleParams", "kind": "Interface" }, + { "name": "GridValueGetterFullParams", "kind": "TypeAlias" }, + { "name": "GridValueGetterParams", "kind": "Interface" }, { "name": "GridValueOptionsParams", "kind": "Interface" }, { "name": "GridValueSetterParams", "kind": "Interface" }, { "name": "GridViewHeadlineIcon", "kind": "Variable" }, From 1eb7dc76a1fe921dd40f2c9200bf5d9dacf25c7f Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 18 Jan 2022 11:49:13 +0100 Subject: [PATCH 32/33] =?UTF-8?q?Code=20review:=20Jos=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../group-pivot/RowGroupingBasicExample.js | 65 ++++++++++++++++ .../group-pivot/RowGroupingBasicExample.tsx | 76 +++++++++++++++++++ .../RowGroupingBasicExample.tsx.preview | 14 ++++ .../data-grid/group-pivot/group-pivot.md | 7 +- 4 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.js create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx create mode 100644 docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.js b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.js new file mode 100644 index 0000000000000..dbbb7bd4160ad --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.js @@ -0,0 +1,65 @@ +import * as React from 'react'; +import { DataGridPro, GridEvents, useGridApiRef } from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = (apiRef, columns, initialModel, leafField) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + + prevModel.current = initialModel; + }); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function RowGroupingBasicExample() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx new file mode 100644 index 0000000000000..fd3136270e91e --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { + DataGridPro, + GridApiRef, + GridColumns, + GridEvents, + GridRowGroupingModel, + useGridApiRef, +} from '@mui/x-data-grid-pro'; +import { useMovieData } from '@mui/x-data-grid-generator'; + +const INITIAL_GROUPING_COLUMN_MODEL = ['company']; + +const useKeepGroupingColumnsHidden = ( + apiRef: GridApiRef, + columns: GridColumns, + initialModel: GridRowGroupingModel, + leafField?: string, +) => { + const prevModel = React.useRef(initialModel); + + React.useEffect(() => { + apiRef.current.subscribeEvent(GridEvents.rowGroupingModelChange, (newModel) => { + apiRef.current.updateColumns([ + ...newModel + .filter((field) => !prevModel.current.includes(field)) + .map((field) => ({ field, hide: true })), + ...prevModel.current + .filter((field) => !newModel.includes(field)) + .map((field) => ({ field, hide: false })), + ]); + prevModel.current = initialModel; + }); + }, [apiRef, initialModel]); + + return React.useMemo( + () => + columns.map((colDef) => + initialModel.includes(colDef.field) || + (leafField && colDef.field === leafField) + ? { ...colDef, hide: true } + : colDef, + ), + [columns, initialModel, leafField], + ); +}; + +export default function RowGroupingBasicExample() { + const data = useMovieData(); + const apiRef = useGridApiRef(); + + const columns = useKeepGroupingColumnsHidden( + apiRef, + data.columns, + INITIAL_GROUPING_COLUMN_MODEL, + ); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview new file mode 100644 index 0000000000000..07bac07ad0a0b --- /dev/null +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md index d75735ef56fde..1529dc16766ee 100644 --- a/docs/src/pages/components/data-grid/group-pivot/group-pivot.md +++ b/docs/src/pages/components/data-grid/group-pivot/group-pivot.md @@ -9,8 +9,9 @@ title: Data Grid - Group & Pivot ## Row grouping [](https://mui.com/store/items/material-ui-pro/) For when you need to group rows based on repeated column values, and/or custom functions. +On the following example, we're grouping all movies based on their production `company` -{{"demo": "pages/components/data-grid/group-pivot/RowGroupingSingleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} +{{"demo": "pages/components/data-grid/group-pivot/RowGroupingBasicExample.js", "bg": "inline", "defaultCodeOpen": false}} > ⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan. > @@ -59,7 +60,7 @@ If you have multiple grouped columns, this column name will be set to "Group". #### Multiple grouping column -To display a column for each grouping criterion, set the `rowGroupingColumnMode` prop to `multiple. +To display a column for each grouping criterion, set the `rowGroupingColumnMode` prop to `multiple`. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingMultipleGroupingCol.js", "bg": "inline", "defaultCodeOpen": false}} @@ -87,7 +88,7 @@ If you want to display some value, you can provide a `leafField` property to the #### Hide the descendant count -Use the `hideDescendantCount` property of the `groupingColDef to hide the number of descendants of a grouping row. +Use the `hideDescendantCount` property of the `groupingColDef` to hide the number of descendants of a grouping row. {{"demo": "pages/components/data-grid/group-pivot/RowGroupingHideDescendantCount.js", "bg": "inline", "defaultCodeOpen": false}} From ff535806e177b3e2b2183c1eb2d113048ca4867a Mon Sep 17 00:00:00 2001 From: delangle Date: Tue, 18 Jan 2022 11:58:38 +0100 Subject: [PATCH 33/33] Work --- .../RowGroupingBasicExample.tsx.preview | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview index 07bac07ad0a0b..3ebe5d5b5a813 100644 --- a/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview +++ b/docs/src/pages/components/data-grid/group-pivot/RowGroupingBasicExample.tsx.preview @@ -1,14 +1,14 @@ \ No newline at end of file