\ 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 (
+
+ );
+ };
+
+ const renderUnGroupingMenuItem = (field: string) => {
+ const ungroupColumn = (event: React.MouseEvent) => {
+ apiRef.current.removeGroupingCriteria(field);
+ if (onClick) {
+ onClick(event);
+ }
+ };
+
+ const name = columnsLookup[field].headerName ?? field;
+
+ return (
+
+ );
+ };
+
+ 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(
+ ,
+ );
+
+ // "Cat A" & "Cat 2" groups are not tested against the "id" filter item
+ expect(getColumnValues(0)).to.deep.equal(['Cat A (1)', 'Cat 2 (1)', '']);
+ });
+ });
+
+ describe('props: groupingColumnMode = "multiple"', () => {
+ 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(
+ ,
+ );
+
+ // "Cat A" & "Cat 2" groups are not tested against the "id" filter item
+ expect(getColumnValues(0)).to.deep.equal(['Cat A (1)', '', '']);
+ expect(getColumnValues(1)).to.deep.equal(['', 'Cat 2 (1)', '']);
+ });
+
+ it('should not filter the groups when filtering with an item that is from another grouping column', () => {
+ 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 (
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(
,
);
@@ -1869,15 +1869,15 @@ describe(' - 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(
,
);
@@ -1993,7 +1993,7 @@ describe(' - 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 (
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+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 (
-
- );
- };
-
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 (
+
+
+ );
+}
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