@mui/x-data-grid-premium 6.0.0-alpha.0 → 6.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/DataGridPremium/DataGridPremium.js +2 -2
  3. package/DataGridPremium/useDataGridPremiumProps.js +1 -1
  4. package/components/GridGroupingCriteriaCell.d.ts +2 -2
  5. package/hooks/features/aggregation/createAggregationLookup.js +20 -43
  6. package/hooks/features/aggregation/gridAggregationUtils.d.ts +12 -7
  7. package/hooks/features/aggregation/gridAggregationUtils.js +72 -63
  8. package/hooks/features/aggregation/useGridAggregationPreProcessors.js +17 -27
  9. package/hooks/features/aggregation/wrapColumnWithAggregation.js +2 -2
  10. package/hooks/features/rowGrouping/createGroupingColDef.js +14 -12
  11. package/hooks/features/rowGrouping/gridRowGroupingUtils.d.ts +11 -2
  12. package/hooks/features/rowGrouping/gridRowGroupingUtils.js +44 -15
  13. package/hooks/features/rowGrouping/useGridRowGrouping.js +7 -5
  14. package/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +29 -46
  15. package/index.js +1 -1
  16. package/legacy/DataGridPremium/DataGridPremium.js +2 -2
  17. package/legacy/DataGridPremium/useDataGridPremiumProps.js +1 -1
  18. package/legacy/hooks/features/aggregation/createAggregationLookup.js +22 -47
  19. package/legacy/hooks/features/aggregation/gridAggregationUtils.js +71 -63
  20. package/legacy/hooks/features/aggregation/useGridAggregationPreProcessors.js +17 -27
  21. package/legacy/hooks/features/aggregation/wrapColumnWithAggregation.js +2 -2
  22. package/legacy/hooks/features/rowGrouping/createGroupingColDef.js +14 -12
  23. package/legacy/hooks/features/rowGrouping/gridRowGroupingUtils.js +46 -18
  24. package/legacy/hooks/features/rowGrouping/useGridRowGrouping.js +7 -5
  25. package/legacy/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +29 -45
  26. package/legacy/index.js +1 -1
  27. package/legacy/themeAugmentation/index.js +3 -0
  28. package/legacy/themeAugmentation/overrides.js +1 -0
  29. package/legacy/themeAugmentation/props.js +1 -0
  30. package/legacy/utils/releaseInfo.js +1 -1
  31. package/models/dataGridPremiumProps.d.ts +3 -3
  32. package/models/gridGroupingValueGetterParams.d.ts +2 -2
  33. package/modern/DataGridPremium/DataGridPremium.js +2 -2
  34. package/modern/DataGridPremium/useDataGridPremiumProps.js +1 -1
  35. package/modern/hooks/features/aggregation/createAggregationLookup.js +22 -37
  36. package/modern/hooks/features/aggregation/gridAggregationUtils.js +72 -61
  37. package/modern/hooks/features/aggregation/useGridAggregationPreProcessors.js +17 -27
  38. package/modern/hooks/features/aggregation/wrapColumnWithAggregation.js +1 -1
  39. package/modern/hooks/features/rowGrouping/createGroupingColDef.js +12 -12
  40. package/modern/hooks/features/rowGrouping/gridRowGroupingUtils.js +44 -11
  41. package/modern/hooks/features/rowGrouping/useGridRowGrouping.js +7 -3
  42. package/modern/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +29 -46
  43. package/modern/index.js +1 -1
  44. package/modern/themeAugmentation/index.js +3 -0
  45. package/modern/themeAugmentation/overrides.js +1 -0
  46. package/modern/themeAugmentation/props.js +1 -0
  47. package/modern/utils/releaseInfo.js +1 -1
  48. package/node/DataGridPremium/DataGridPremium.js +2 -2
  49. package/node/DataGridPremium/useDataGridPremiumProps.js +1 -1
  50. package/node/hooks/features/aggregation/createAggregationLookup.js +19 -42
  51. package/node/hooks/features/aggregation/gridAggregationUtils.js +74 -63
  52. package/node/hooks/features/aggregation/useGridAggregationPreProcessors.js +17 -27
  53. package/node/hooks/features/aggregation/wrapColumnWithAggregation.js +2 -2
  54. package/node/hooks/features/rowGrouping/createGroupingColDef.js +14 -12
  55. package/node/hooks/features/rowGrouping/gridRowGroupingUtils.js +48 -16
  56. package/node/hooks/features/rowGrouping/useGridRowGrouping.js +6 -4
  57. package/node/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +27 -47
  58. package/node/index.js +1 -1
  59. package/node/themeAugmentation/index.js +31 -0
  60. package/node/themeAugmentation/overrides.js +5 -0
  61. package/node/themeAugmentation/props.js +5 -0
  62. package/node/utils/releaseInfo.js +1 -1
  63. package/package.json +3 -3
  64. package/themeAugmentation/index.d.ts +2 -0
  65. package/themeAugmentation/index.js +3 -0
  66. package/themeAugmentation/overrides.d.ts +8 -0
  67. package/themeAugmentation/overrides.js +1 -0
  68. package/themeAugmentation/package.json +6 -0
  69. package/themeAugmentation/props.d.ts +19 -0
  70. package/themeAugmentation/props.js +1 -0
  71. package/utils/releaseInfo.js +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,139 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 6.0.0-alpha.1
7
+
8
+ _Sep 29, 2022_
9
+
10
+ We'd like to offer a big thanks to the 8 contributors who made this release possible. Here are some highlights ✨:
11
+
12
+ - 🚀 Better support for custom overlays (#5808) @cherniavskii
13
+ - 🖨️ Improve print export (#6273) @oliviertassinari
14
+ - 🎁 Reduce confusion when initializing pickers with a date value (#6170) @flaviendelangle
15
+ - 📚 Documentation improvements
16
+ - 🐞 Bugfixes
17
+
18
+ ### `@mui/x-data-grid@v6.0.0-alpha.1` / `@mui/x-data-grid-pro@v6.0.0-alpha.1` / `@mui/x-data-grid-premium@v6.0.0-alpha.1`
19
+
20
+ #### Breaking changes
21
+
22
+ - New internal rows structure for v6 (#4927) @flaviendelangle
23
+
24
+ Some selectors related to the rows have been renamed to better describe the type of rows they are returning:
25
+
26
+ ```diff
27
+ -const result = gridRowsIdToIdLookupSelector(apiRef);
28
+ +const result = gridRowsDataRowIdToIdLookupSelector(apiRef);
29
+ ```
30
+
31
+ ```diff
32
+ -const result = gridRowTreeDepthSelector(apiRef);
33
+ +const result = gridRowMaximumTreeDepthSelector(apiRef);
34
+ ```
35
+
36
+ The format of the tree nodes (the element accessible in `params.node` or with the `apiRef.current.getRowNode` method) have changed.
37
+ You have a new `type` property, which can be useful, for example, to apply custom behavior on groups.
38
+ Here is an example of the old and new approach showing how to apply a custom value formatter in groups for the grouping column:
39
+
40
+ ```diff
41
+ <DataGridPremium
42
+ groupingColDef={() => ({
43
+ valueFormatter: (params) => {
44
+ if (params.id == null) {
45
+ return params.value;
46
+ }
47
+
48
+ const rowNode = apiRef.current.getRowNode(params.id!)!;
49
+ - if (rowNode.children?.length) {
50
+ + if (rowNode.type === 'group') {
51
+ return `by ${rowNode.groupingKey ?? ''}`;
52
+ }
53
+
54
+ return params.value;
55
+ }
56
+ })}
57
+ />
58
+ ```
59
+
60
+ - The `GridFeatureModeConstant` constant no longer exists (#6077) @DanailH
61
+
62
+ ```diff
63
+ -import { GridFeatureModeConstant } from '@mui/x-data-grid';
64
+ ```
65
+
66
+ #### Changes
67
+
68
+ - [DataGrid] Fix `GridPagination` props typing (#6238) @cherniavskii
69
+ - [DataGrid] Fix `GridRow` not forwarding `ref` to the root element (#6274) @cherniavskii
70
+ - [DataGrid] Fix `undefined` value being showed in filter button tooltip text (#6259) @cherniavskii
71
+ - [DataGrid] Fix blank space when changing page with dynamic row height (#6049) @m4theushw
72
+ - [DataGrid] New internal rows structure for v6 (#4927) @flaviendelangle
73
+ - [DataGrid] Revert cell/row mode if `processRowUpdate` fails (#6185) @m4theushw
74
+ - [DataGrid] Rework overlays layout (#5808) @cherniavskii
75
+ - [DataGrid] Improve print support (#6273) @oliviertassinari
76
+ - [DataGridPremium] Add missing `themeAugmentation` module (#6270) @cherniavskii
77
+
78
+ ### `@mui/x-date-pickers@v6.0.0-alpha.1` / `@mui/x-date-pickers-pro@v6.0.0-alpha.1`
79
+
80
+ #### Breaking changes
81
+
82
+ - [pickers] Do not support unparsed date formats anymore (#6170) @flaviendelangle
83
+
84
+ The `value` prop of the pickers now expects a parsed value.
85
+ Until now, it was possible to provide any format that your date management library was able to parse.
86
+ For instance, you could pass `value={new Date()}` when using `AdapterDayjs`.
87
+
88
+ This brought a lot of confusion so we decided to remove this behavior.
89
+ The format expected by the `value` prop is now the same as for any other prop holding a date.
90
+ Here is the syntax to initialize a date picker at the current date for each adapter:
91
+
92
+ ```tsx
93
+ // Date-fns
94
+ <DatePicker value={new Date()} />
95
+
96
+ // Dayjs
97
+ import dayjs from 'dayjs'
98
+ <DatePicker value={dayjs()} />
99
+
100
+ // Moment
101
+ import moment from 'moment'
102
+ <DatePicker value={moment()} />
103
+
104
+ // Luxon
105
+ import { DateTime } from 'luxon'
106
+ <DatePicker value={DateTime.now()} />
107
+ ```
108
+
109
+ #### Changes
110
+
111
+ - [DatePicker] Respect `minDate` and `maxDate` when opening a `DatePicker` or `DateTimePicker` (#6309) @alexfauquette
112
+ - [DateTimePicker] Fix validation with `shouldDisableMonth` and `shouldDisableYear` (#6266) @flaviendelangle
113
+ - [TimePicker] Add support for `disablePast` and `disableFuture` validation props (#6226) @LukasTy
114
+ - [CalendarPicker] Prevent getting focus when `autoFocus=false` (#6304) @alexfauquette
115
+ - [DateField] Extend moment adapter to support `expandFormat` and `formatTokenMap` (#6215) @alexfauquette
116
+ - [pickers] Allow to control the selected sections (#6209, #6307) @flaviendelangle
117
+ - [pickers] Do not loose the value of date sections not present in the format in the new field components (#6141) @flaviendelangle
118
+ - [pickers] Do not support unparsed date formats anymore (#6170) @flaviendelangle
119
+ - [pickers] Support slots on the `DateField` component (#6048) @flaviendelangle
120
+ - [pickers] Support Luxon v3 in `AdapterLuxon` (#6069) @alexfauquette
121
+ - [pickers] New components `TimeField` and `DateTimeField` (#6312) @flaviendelangle
122
+ - [pickers] Support basic mobile edition on new field components (#5958) @flaviendelangle
123
+
124
+ ### Docs
125
+
126
+ - [docs] Fix issue in DataGrid/DataGridPro row styling demo (#6264) @MBilalShafi
127
+ - [docs] Improve pickers Getting Started examples (#6292) @flaviendelangle
128
+ - [docs] Pass model change callbacks in controlled grid editing demos (#6296) @cherniavskii
129
+ - [docs] Update the CodeSandbox to use the `next` branch (#6275) @oliviertassinari
130
+
131
+ ### Core
132
+
133
+ - [core] Fix typing error (#6291) @flaviendelangle
134
+ - [core] Fix typo in the state updater of `useField` (#6311) @flaviendelangle
135
+ - [core] Remove `GridFeatureModeConstant` (#6077) @DanailH
136
+ - [core] Simplify testing architecture (#6043) @flaviendelangle
137
+ - [test] Skip test in Chrome non-headless and Edge (#6318) @m4theushw
138
+
6
139
  ## 6.0.0-alpha.0
7
140
 
8
141
  _Sep 22, 2022_
@@ -344,7 +344,7 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
344
344
 
345
345
  /**
346
346
  * Determines the position of an aggregated value.
347
- * @param {GridRowTreeNodeConfig | null} groupNode The current group (`null` being the top level group).
347
+ * @param {GridGroupNode} groupNode The current group.
348
348
  * @returns {GridAggregationPosition | null} Position of the aggregated value (if `null`, the group will not be aggregated).
349
349
  * @default `(groupNode) => groupNode == null ? 'footer' : 'inline'`
350
350
  */
@@ -476,7 +476,7 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
476
476
  /**
477
477
  * Determines if a group should be expanded after its creation.
478
478
  * This prop takes priority over the `defaultGroupingExpansionDepth` prop.
479
- * @param {GridRowTreeNodeConfig} node The node of the group to test.
479
+ * @param {GridGroupNode} node The node of the group to test.
480
480
  * @returns {boolean} A boolean indicating if the group is expanded.
481
481
  */
482
482
  isGroupExpandedByDefault: PropTypes.func,
@@ -13,7 +13,7 @@ export const DATA_GRID_PREMIUM_PROPS_DEFAULT_VALUES = _extends({}, DATA_GRID_PRO
13
13
  rowGroupingColumnMode: 'single',
14
14
  aggregationFunctions: GRID_AGGREGATION_FUNCTIONS,
15
15
  aggregationRowsScope: 'filtered',
16
- getAggregationPosition: groupNode => groupNode == null ? 'footer' : 'inline'
16
+ getAggregationPosition: groupNode => groupNode.depth === -1 ? 'footer' : 'inline'
17
17
  });
18
18
  export const useDataGridPremiumProps = inProps => {
19
19
  const themedProps = useThemeProps({
@@ -1,6 +1,6 @@
1
1
  /// <reference types="react" />
2
- import { GridRenderCellParams } from '@mui/x-data-grid-pro';
3
- interface GridGroupingCriteriaCellProps extends GridRenderCellParams {
2
+ import { GridRenderCellParams, GridGroupNode } from '@mui/x-data-grid-pro';
3
+ interface GridGroupingCriteriaCellProps extends GridRenderCellParams<any, any, any, GridGroupNode> {
4
4
  hideDescendantCount?: boolean;
5
5
  }
6
6
  export declare const GridGroupingCriteriaCell: (props: GridGroupingCriteriaCellProps) => JSX.Element;
@@ -1,4 +1,4 @@
1
- import { gridColumnLookupSelector, gridFilteredRowsLookupSelector, gridRowIdsSelector, gridRowTreeSelector } from '@mui/x-data-grid-pro';
1
+ import { gridColumnLookupSelector, gridFilteredRowsLookupSelector, gridRowTreeSelector, GRID_ROOT_GROUP_ID } from '@mui/x-data-grid-pro';
2
2
  import { getAggregationRules } from './gridAggregationUtils';
3
3
  import { gridAggregationModelSelector } from './gridAggregationSelectors';
4
4
 
@@ -9,22 +9,12 @@ const getAggregationCellValue = ({
9
9
  aggregationFunction,
10
10
  aggregationRowsScope
11
11
  }) => {
12
- const rowTree = gridRowTreeSelector(apiRef);
13
12
  const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);
14
- let rowIds; // TODO: Add custom root id
15
-
16
- if (groupId === '') {
17
- rowIds = gridRowIdsSelector(apiRef).filter(rowId => !rowTree[rowId].isAutoGenerated);
18
- } else {
19
- rowIds = apiRef.current.getRowGroupChildren({
20
- groupId
21
- });
22
- }
23
-
13
+ const rowIds = apiRef.current.getRowGroupChildren({
14
+ groupId
15
+ });
24
16
  const values = [];
25
17
  rowIds.forEach(rowId => {
26
- var _rowNode$children;
27
-
28
18
  if (aggregationRowsScope === 'filtered' && filteredRowsLookup[rowId] === false) {
29
19
  return;
30
20
  } // If the row is a group, we want to aggregate based on its children
@@ -38,7 +28,7 @@ const getAggregationCellValue = ({
38
28
 
39
29
  const rowNode = apiRef.current.getRowNode(rowId);
40
30
 
41
- if ((_rowNode$children = rowNode.children) != null && _rowNode$children.length) {
31
+ if (rowNode.type === 'group') {
42
32
  return;
43
33
  }
44
34
 
@@ -95,26 +85,26 @@ export const createAggregationLookup = ({
95
85
  }
96
86
 
97
87
  const aggregationLookup = {};
98
- const rowIds = gridRowIdsSelector(apiRef);
99
88
  const rowTree = gridRowTreeSelector(apiRef);
100
89
 
101
- for (let i = 0; i < rowIds.length; i += 1) {
102
- var _node$children;
90
+ const createGroupAggregationLookup = groupNode => {
91
+ for (let i = 0; i < groupNode.children.length; i += 1) {
92
+ const childId = groupNode.children[i];
93
+ const childNode = rowTree[childId];
103
94
 
104
- const rowId = rowIds[i];
105
- const node = rowTree[rowId];
106
- const hasChildren = (_node$children = node.children) == null ? void 0 : _node$children.some(childId => {
107
- var _rowTree$childId$posi;
95
+ if (childNode.type === 'group') {
96
+ createGroupAggregationLookup(childNode);
97
+ }
98
+ }
108
99
 
109
- return ((_rowTree$childId$posi = rowTree[childId].position) != null ? _rowTree$childId$posi : 'body') === 'body';
110
- });
100
+ const hasAggregableChildren = groupNode.children.length;
111
101
 
112
- if (hasChildren) {
113
- const position = getAggregationPosition(node);
102
+ if (hasAggregableChildren) {
103
+ const position = getAggregationPosition(groupNode);
114
104
 
115
105
  if (position != null) {
116
- aggregationLookup[rowId] = getGroupAggregatedValue({
117
- groupId: rowId,
106
+ aggregationLookup[groupNode.id] = getGroupAggregatedValue({
107
+ groupId: groupNode.id,
118
108
  apiRef,
119
109
  aggregatedFields,
120
110
  aggregationRowsScope,
@@ -123,21 +113,8 @@ export const createAggregationLookup = ({
123
113
  });
124
114
  }
125
115
  }
126
- } // TODO: Add custom root id
127
-
128
-
129
- const position = getAggregationPosition(null);
130
-
131
- if (position != null) {
132
- aggregationLookup[''] = getGroupAggregatedValue({
133
- groupId: '',
134
- apiRef,
135
- aggregatedFields,
136
- aggregationRowsScope,
137
- aggregationRules,
138
- position
139
- });
140
- }
116
+ };
141
117
 
118
+ createGroupAggregationLookup(rowTree[GRID_ROOT_GROUP_ID]);
142
119
  return aggregationLookup;
143
120
  };
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { GridColDef, GridRowId } from '@mui/x-data-grid-pro';
3
- import { GridColumnRawLookup, GridRowTreeCreationValue } from '@mui/x-data-grid-pro/internals';
3
+ import { GridColumnRawLookup, GridHydrateRowsValue } from '@mui/x-data-grid-pro/internals';
4
4
  import { GridAggregationFunction, GridAggregationModel, GridAggregationRule, GridAggregationRules } from './gridAggregationInterfaces';
5
5
  import { GridStatePremium } from '../../../models/gridStatePremium';
6
6
  import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps';
@@ -22,15 +22,19 @@ export declare const getAggregationRules: ({ columnsLookup, aggregationModel, ag
22
22
  aggregationModel: GridAggregationModel;
23
23
  aggregationFunctions: Record<string, GridAggregationFunction>;
24
24
  }) => GridAggregationRules;
25
+ interface AddFooterRowsParams {
26
+ groupingParams: GridHydrateRowsValue;
27
+ getAggregationPosition: DataGridPremiumProcessedProps['getAggregationPosition'];
28
+ /**
29
+ * If `true`, there are some aggregation rules to apply
30
+ */
31
+ hasAggregationRule: boolean;
32
+ apiRef: React.MutableRefObject<GridApiPremium>;
33
+ }
25
34
  /**
26
35
  * Add a footer for each group that has at least one column with an aggregated value.
27
36
  */
28
- export declare const addFooterRows: ({ groupingParams, aggregationRules, getAggregationPosition, apiRef, }: {
29
- groupingParams: GridRowTreeCreationValue;
30
- aggregationRules: GridAggregationRules;
31
- getAggregationPosition: DataGridPremiumProcessedProps['getAggregationPosition'];
32
- apiRef: React.MutableRefObject<GridApiPremium>;
33
- }) => GridRowTreeCreationValue;
37
+ export declare const addFooterRows: ({ groupingParams, apiRef, getAggregationPosition, hasAggregationRule, }: AddFooterRowsParams) => GridHydrateRowsValue;
34
38
  /**
35
39
  * Compares two sets of aggregation rules to determine if they are equal or not.
36
40
  */
@@ -39,3 +43,4 @@ export declare const getAggregationFunctionLabel: ({ apiRef, aggregationRule, }:
39
43
  apiRef: React.MutableRefObject<GridApiPremium>;
40
44
  aggregationRule: GridAggregationRule;
41
45
  }) => string;
46
+ export {};
@@ -1,6 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { capitalize } from '@mui/material';
3
- import { addPinnedRow, isDeepEqual } from '@mui/x-data-grid-pro/internals';
3
+ import { GRID_ROOT_GROUP_ID } from '@mui/x-data-grid-pro';
4
+ import { addPinnedRow, isDeepEqual, insertNodeInTree, removeNodeFromTree } from '@mui/x-data-grid-pro/internals';
4
5
  export const GRID_AGGREGATION_ROOT_FOOTER_ROW_ID = 'auto-generated-group-footer-root';
5
6
  export const getAggregationFooterRowIdFromGroupId = groupId => {
6
7
  if (groupId == null) {
@@ -65,85 +66,93 @@ export const getAggregationRules = ({
65
66
  });
66
67
  return aggregationRules;
67
68
  };
69
+
68
70
  /**
69
71
  * Add a footer for each group that has at least one column with an aggregated value.
70
72
  */
71
-
72
73
  export const addFooterRows = ({
73
74
  groupingParams,
74
- aggregationRules,
75
+ apiRef,
75
76
  getAggregationPosition,
76
- apiRef
77
+ hasAggregationRule
77
78
  }) => {
78
- if (Object.keys(aggregationRules).length === 0) {
79
- return groupingParams;
80
- }
81
-
82
- const ids = [...groupingParams.ids];
83
-
84
- const idRowsLookup = _extends({}, groupingParams.idRowsLookup);
85
-
86
- const tree = _extends({}, groupingParams.tree);
87
-
88
- const addGroupFooter = groupNode => {
89
- var _groupNode$id;
90
-
91
- const groupId = (_groupNode$id = groupNode == null ? void 0 : groupNode.id) != null ? _groupNode$id : null;
79
+ let newGroupingParams = _extends({}, groupingParams, {
80
+ tree: _extends({}, groupingParams.tree),
81
+ treeDepths: _extends({}, groupingParams.treeDepths)
82
+ });
92
83
 
93
- if (getAggregationPosition(groupNode) !== 'footer') {
94
- return;
84
+ const updateChildGroupFooter = groupNode => {
85
+ const shouldHaveFooter = hasAggregationRule && getAggregationPosition(groupNode) === 'footer';
86
+
87
+ if (shouldHaveFooter) {
88
+ const footerId = getAggregationFooterRowIdFromGroupId(groupNode.id);
89
+
90
+ if (groupNode.footerId !== footerId) {
91
+ if (groupNode.footerId != null) {
92
+ removeNodeFromTree({
93
+ node: newGroupingParams.tree[groupNode.footerId],
94
+ tree: newGroupingParams.tree,
95
+ treeDepths: newGroupingParams.treeDepths
96
+ });
97
+ }
98
+
99
+ const footerNode = {
100
+ id: footerId,
101
+ parent: groupNode.id,
102
+ depth: groupNode ? groupNode.depth + 1 : 0,
103
+ type: 'footer'
104
+ };
105
+ insertNodeInTree({
106
+ node: footerNode,
107
+ tree: newGroupingParams.tree,
108
+ treeDepths: newGroupingParams.treeDepths
109
+ });
110
+ }
111
+ } else if (groupNode.footerId != null) {
112
+ removeNodeFromTree({
113
+ node: newGroupingParams.tree[groupNode.footerId],
114
+ tree: newGroupingParams.tree,
115
+ treeDepths: newGroupingParams.treeDepths
116
+ });
117
+ newGroupingParams.tree[groupNode.id] = _extends({}, newGroupingParams.tree[groupNode.id], {
118
+ footerId: null
119
+ });
95
120
  }
96
-
97
- const footerId = getAggregationFooterRowIdFromGroupId(groupId);
98
- ids.push(footerId);
99
- idRowsLookup[footerId] = {};
100
- tree[footerId] = {
101
- id: footerId,
102
- isAutoGenerated: true,
103
- parent: groupId,
104
- depth: groupNode ? groupNode.depth + 1 : 0,
105
- groupingKey: null,
106
- groupingField: null,
107
- position: 'footer'
108
- };
109
-
110
- if (groupId != null) {
111
- tree[groupId] = _extends({}, tree[groupId], {
112
- footerId
121
+ };
122
+
123
+ const updateRootGroupFooter = groupNode => {
124
+ const shouldHaveFooter = hasAggregationRule && getAggregationPosition(groupNode) === 'footer';
125
+
126
+ if (shouldHaveFooter) {
127
+ newGroupingParams = addPinnedRow({
128
+ groupingParams: newGroupingParams,
129
+ rowModel: undefined,
130
+ rowId: getAggregationFooterRowIdFromGroupId(null),
131
+ position: 'bottom',
132
+ apiRef,
133
+ isAutoGenerated: true
113
134
  });
114
135
  }
115
- }; // If the tree is flat, we don't need to loop through the rows
136
+ };
116
137
 
138
+ const updateGroupFooter = groupNode => {
139
+ if (groupNode.id === GRID_ROOT_GROUP_ID) {
140
+ updateRootGroupFooter(groupNode);
141
+ } else {
142
+ updateChildGroupFooter(groupNode);
143
+ }
117
144
 
118
- if (groupingParams.treeDepth > 1) {
119
- groupingParams.ids.forEach(parentId => {
120
- const parentNode = tree[parentId];
145
+ groupNode.children.forEach(childId => {
146
+ const childNode = newGroupingParams.tree[childId];
121
147
 
122
- if (parentNode.depth === groupingParams.treeDepth - 1) {
123
- return;
148
+ if (childNode.type === 'group') {
149
+ updateGroupFooter(childNode);
124
150
  }
125
-
126
- addGroupFooter(parentNode);
127
- });
128
- }
129
-
130
- let newGroupingParams = _extends({}, groupingParams, {
131
- tree,
132
- idRowsLookup,
133
- ids
134
- });
135
-
136
- if (getAggregationPosition(null) === 'footer') {
137
- newGroupingParams = addPinnedRow({
138
- groupingParams: newGroupingParams,
139
- rowModel: {},
140
- rowId: getAggregationFooterRowIdFromGroupId(null),
141
- position: 'bottom',
142
- apiRef
143
151
  });
144
- }
152
+ };
145
153
 
146
- return _extends({}, groupingParams, newGroupingParams);
154
+ updateGroupFooter(newGroupingParams.tree[GRID_ROOT_GROUP_ID]);
155
+ return newGroupingParams;
147
156
  };
148
157
  /**
149
158
  * Compares two sets of aggregation rules to determine if they are equal or not.
@@ -47,36 +47,26 @@ export const useGridAggregationPreProcessors = (apiRef, props) => {
47
47
  apiRef.current.unstable_caches.aggregation.rulesOnLastColumnHydration = aggregationRules;
48
48
  return columnsState;
49
49
  }, [apiRef, props.aggregationFunctions, props.disableAggregation]);
50
- const addGroupFooterRows = React.useCallback(groupingParams => {
51
- let newGroupingParams;
52
- let rulesOnLastRowHydration;
50
+ const addGroupFooterRows = React.useCallback(value => {
51
+ const aggregationRules = props.disableAggregation ? {} : getAggregationRules({
52
+ columnsLookup: gridColumnLookupSelector(apiRef),
53
+ aggregationModel: gridAggregationModelSelector(apiRef),
54
+ aggregationFunctions: props.aggregationFunctions
55
+ });
56
+ const hasAggregationRule = Object.keys(aggregationRules).length > 0; // If we did not have any aggregation footer before, and we still don't have any,
57
+ // Then we can skip this step
53
58
 
54
- if (props.disableAggregation) {
55
- newGroupingParams = groupingParams;
56
- rulesOnLastRowHydration = {};
57
- } else {
58
- const aggregationRules = getAggregationRules({
59
- columnsLookup: gridColumnLookupSelector(apiRef),
60
- aggregationModel: gridAggregationModelSelector(apiRef),
61
- aggregationFunctions: props.aggregationFunctions
62
- });
63
- rulesOnLastRowHydration = aggregationRules; // If no column have an aggregation rule
64
- // Then don't create the footer rows
65
-
66
- if (Object.values(aggregationRules).length === 0) {
67
- newGroupingParams = groupingParams;
68
- } else {
69
- newGroupingParams = addFooterRows({
70
- groupingParams,
71
- aggregationRules,
72
- getAggregationPosition: props.getAggregationPosition,
73
- apiRef
74
- });
75
- }
59
+ if (Object.keys(apiRef.current.unstable_caches.aggregation.rulesOnLastRowHydration).length === 0 && !hasAggregationRule) {
60
+ return value;
76
61
  }
77
62
 
78
- apiRef.current.unstable_caches.aggregation.rulesOnLastRowHydration = rulesOnLastRowHydration;
79
- return newGroupingParams;
63
+ apiRef.current.unstable_caches.aggregation.rulesOnLastRowHydration = aggregationRules;
64
+ return addFooterRows({
65
+ apiRef,
66
+ groupingParams: value,
67
+ getAggregationPosition: props.getAggregationPosition,
68
+ hasAggregationRule
69
+ });
80
70
  }, [apiRef, props.disableAggregation, props.getAggregationPosition, props.aggregationFunctions]);
81
71
  const addColumnMenuButtons = React.useCallback((initialValue, column) => {
82
72
  if (props.disableAggregation) {
@@ -161,12 +161,12 @@ export const wrapColumnWithAggregationValue = ({
161
161
  aggregationRule
162
162
  }) => {
163
163
  const getCellAggregationResult = (id, field) => {
164
- var _rowNode$children, _rowNode$parent, _gridAggregationLooku;
164
+ var _rowNode$parent, _gridAggregationLooku;
165
165
 
166
166
  let cellAggregationPosition = null;
167
167
  const rowNode = apiRef.current.getRowNode(id);
168
168
 
169
- if ((_rowNode$children = rowNode.children) != null && _rowNode$children.length) {
169
+ if (rowNode.type === 'group') {
170
170
  cellAggregationPosition = 'inline';
171
171
  } else if (id.toString().startsWith('auto-generated-group-footer-')) {
172
172
  cellAggregationPosition = 'footer';
@@ -27,9 +27,11 @@ const GROUPING_COL_DEF_FORCED_PROPERTIES = {
27
27
  */
28
28
 
29
29
  const groupingFieldIndexComparator = (v1, v2, cellParams1, cellParams2) => {
30
+ var _groupingField, _groupingField2;
31
+
30
32
  const model = gridRowGroupingSanitizedModelSelector(cellParams1.api.state, cellParams1.api.instanceId);
31
- const groupingField1 = cellParams1.rowNode.groupingField;
32
- const groupingField2 = cellParams2.rowNode.groupingField;
33
+ const groupingField1 = (_groupingField = cellParams1.rowNode.groupingField) != null ? _groupingField : null;
34
+ const groupingField2 = (_groupingField2 = cellParams2.rowNode.groupingField) != null ? _groupingField2 : null;
33
35
 
34
36
  if (groupingField1 === groupingField2) {
35
37
  return 0;
@@ -72,7 +74,7 @@ const getLeafProperties = leafColDef => {
72
74
  })),
73
75
  sortComparator: (v1, v2, cellParams1, cellParams2) => {
74
76
  // We only want to sort the leaves
75
- if (cellParams1.rowNode.groupingField === null && cellParams2.rowNode.groupingField === null) {
77
+ if (cellParams1.rowNode.type === 'leaf' && cellParams2.rowNode.type === 'leaf') {
76
78
  return leafColDef.sortComparator(v1, v2, cellParams1, cellParams2);
77
79
  }
78
80
 
@@ -89,7 +91,7 @@ const getGroupingCriteriaProperties = (groupedByColDef, applyHeaderName) => {
89
91
  filterable: groupedByColDef.filterable,
90
92
  sortComparator: (v1, v2, cellParams1, cellParams2) => {
91
93
  // We only want to sort the groups of the current grouping criteria
92
- if (cellParams1.rowNode.groupingField === groupedByColDef.field && cellParams2.rowNode.groupingField === groupedByColDef.field) {
94
+ if (cellParams1.rowNode.type === 'group' && cellParams1.rowNode.groupingField === groupedByColDef.field && cellParams2.rowNode.type === 'group' && cellParams2.rowNode.groupingField === groupedByColDef.field) {
93
95
  return groupedByColDef.sortComparator(v1, v2, cellParams1, cellParams2);
94
96
  }
95
97
 
@@ -144,12 +146,12 @@ export const createGroupingColDefForOneGroupingCriteria = ({
144
146
  width: Math.max(((_groupedByColDef$widt = groupedByColDef.width) != null ? _groupedByColDef$widt : GRID_STRING_COL_DEF.width) + 40, (_leafColDef$width = leafColDef == null ? void 0 : leafColDef.width) != null ? _leafColDef$width : 0),
145
147
  renderCell: params => {
146
148
  // Render footer
147
- if (params.rowNode.position === 'footer') {
149
+ if (params.rowNode.type === 'footer' || params.rowNode.type === 'pinnedRow') {
148
150
  return /*#__PURE__*/_jsx(GridGroupingColumnFooterCell, _extends({}, params));
149
151
  } // Render leaves
150
152
 
151
153
 
152
- if (params.rowNode.groupingField == null) {
154
+ if (params.rowNode.type === 'leaf') {
153
155
  if (leafColDef) {
154
156
  const leafParams = _extends({}, params.api.getCellParams(params.id, leafField), {
155
157
  api: params.api
@@ -175,11 +177,11 @@ export const createGroupingColDefForOneGroupingCriteria = ({
175
177
  return '';
176
178
  },
177
179
  valueGetter: params => {
178
- if (!params.rowNode) {
180
+ if (!params.rowNode || params.rowNode.type === 'footer' || params.rowNode.type === 'pinnedRow') {
179
181
  return undefined;
180
182
  }
181
183
 
182
- if (params.rowNode.groupingField == null) {
184
+ if (params.rowNode.type === 'leaf') {
183
185
  if (leafColDef) {
184
186
  return params.api.getCellValue(params.id, leafField);
185
187
  }
@@ -250,12 +252,12 @@ export const createGroupingColDefForAllGroupingCriteria = ({
250
252
  }), (_leafColDef$width2 = leafColDef == null ? void 0 : leafColDef.width) != null ? _leafColDef$width2 : 0),
251
253
  renderCell: params => {
252
254
  // Render footer
253
- if (params.rowNode.position === 'footer') {
255
+ if (params.rowNode.type === 'footer' || params.rowNode.type === 'pinnedRow') {
254
256
  return /*#__PURE__*/_jsx(GridGroupingColumnFooterCell, _extends({}, params));
255
257
  } // Render the leaves
256
258
 
257
259
 
258
- if (params.rowNode.groupingField == null) {
260
+ if (params.rowNode.type === 'leaf') {
259
261
  if (leafColDef) {
260
262
  const leafParams = _extends({}, params.api.getCellParams(params.id, leafField), {
261
263
  api: params.api
@@ -277,11 +279,11 @@ export const createGroupingColDefForAllGroupingCriteria = ({
277
279
  }));
278
280
  },
279
281
  valueGetter: params => {
280
- if (!params.rowNode) {
282
+ if (!params.rowNode || params.rowNode.type === 'footer' || params.rowNode.type === 'pinnedRow') {
281
283
  return undefined;
282
284
  }
283
285
 
284
- if (params.rowNode.groupingField == null) {
286
+ if (params.rowNode.type === 'leaf') {
285
287
  if (leafColDef) {
286
288
  return params.api.getCellValue(params.id, leafField);
287
289
  }