@mui/x-data-grid-premium 5.16.0 → 5.17.2

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 (59) hide show
  1. package/CHANGELOG.md +138 -1
  2. package/DataGridPremium/DataGridPremium.js +17 -0
  3. package/DataGridPremium/useDataGridPremiumComponent.js +2 -1
  4. package/hooks/features/aggregation/createAggregationLookup.js +15 -0
  5. package/hooks/features/aggregation/gridAggregationUtils.d.ts +1 -1
  6. package/hooks/features/aggregation/gridAggregationUtils.js +6 -6
  7. package/hooks/features/aggregation/useGridAggregation.js +3 -3
  8. package/hooks/features/aggregation/wrapColumnWithAggregation.js +4 -3
  9. package/hooks/features/export/gridExcelExportInterface.d.ts +5 -0
  10. package/hooks/features/export/serializer/excelSerializer.d.ts +1 -0
  11. package/hooks/features/export/serializer/excelSerializer.js +72 -0
  12. package/hooks/features/export/useGridExcelExport.js +2 -1
  13. package/hooks/features/rowGrouping/gridRowGroupingInterfaces.d.ts +7 -1
  14. package/hooks/features/rowGrouping/gridRowGroupingUtils.d.ts +11 -2
  15. package/hooks/features/rowGrouping/gridRowGroupingUtils.js +35 -1
  16. package/hooks/features/rowGrouping/useGridRowGrouping.js +12 -8
  17. package/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +19 -12
  18. package/index.js +1 -1
  19. package/legacy/DataGridPremium/DataGridPremium.js +17 -0
  20. package/legacy/DataGridPremium/useDataGridPremiumComponent.js +2 -1
  21. package/legacy/hooks/features/aggregation/createAggregationLookup.js +15 -0
  22. package/legacy/hooks/features/aggregation/gridAggregationUtils.js +6 -6
  23. package/legacy/hooks/features/aggregation/useGridAggregation.js +3 -3
  24. package/legacy/hooks/features/aggregation/wrapColumnWithAggregation.js +4 -3
  25. package/legacy/hooks/features/export/serializer/excelSerializer.js +87 -8
  26. package/legacy/hooks/features/export/useGridExcelExport.js +2 -1
  27. package/legacy/hooks/features/rowGrouping/gridRowGroupingUtils.js +39 -1
  28. package/legacy/hooks/features/rowGrouping/useGridRowGrouping.js +12 -8
  29. package/legacy/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +19 -12
  30. package/legacy/index.js +1 -1
  31. package/legacy/utils/releaseInfo.js +1 -1
  32. package/modern/DataGridPremium/DataGridPremium.js +17 -0
  33. package/modern/DataGridPremium/useDataGridPremiumComponent.js +2 -1
  34. package/modern/hooks/features/aggregation/createAggregationLookup.js +13 -0
  35. package/modern/hooks/features/aggregation/gridAggregationUtils.js +6 -6
  36. package/modern/hooks/features/aggregation/useGridAggregation.js +3 -3
  37. package/modern/hooks/features/aggregation/wrapColumnWithAggregation.js +3 -2
  38. package/modern/hooks/features/export/serializer/excelSerializer.js +68 -0
  39. package/modern/hooks/features/export/useGridExcelExport.js +1 -0
  40. package/modern/hooks/features/rowGrouping/gridRowGroupingUtils.js +31 -1
  41. package/modern/hooks/features/rowGrouping/useGridRowGrouping.js +12 -8
  42. package/modern/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +19 -12
  43. package/modern/index.js +1 -1
  44. package/modern/utils/releaseInfo.js +1 -1
  45. package/node/DataGridPremium/DataGridPremium.js +17 -0
  46. package/node/DataGridPremium/useDataGridPremiumComponent.js +1 -0
  47. package/node/hooks/features/aggregation/createAggregationLookup.js +15 -0
  48. package/node/hooks/features/aggregation/gridAggregationUtils.js +8 -8
  49. package/node/hooks/features/aggregation/useGridAggregation.js +2 -2
  50. package/node/hooks/features/aggregation/wrapColumnWithAggregation.js +4 -3
  51. package/node/hooks/features/export/serializer/excelSerializer.js +72 -0
  52. package/node/hooks/features/export/useGridExcelExport.js +2 -1
  53. package/node/hooks/features/rowGrouping/gridRowGroupingUtils.js +43 -3
  54. package/node/hooks/features/rowGrouping/useGridRowGrouping.js +9 -5
  55. package/node/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +18 -11
  56. package/node/index.js +1 -1
  57. package/node/utils/releaseInfo.js +1 -1
  58. package/package.json +4 -4
  59. package/utils/releaseInfo.js +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,143 @@
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
+ ## 5.17.2
7
+
8
+ _Sep 9, 2022_
9
+
10
+ This release will the last regular release for our `v5` packages.
11
+ From now on, we'll be focusing on developing MUI X v6.
12
+ You can check the [roadmap](https://github.com/mui/mui-x/projects/1) for more details on what's coming next.
13
+
14
+ And if you'd like to help, please consider volunteering to give us a [user interview](https://docs.google.com/forms/d/11L_zxL7oD_B-ZrZDuSyIkUzJLzOTUU2M4vHXxMVtWhU/edit).
15
+ We'd love to know more about your use cases, pain points and expectations for the future.
16
+
17
+ The `v5` packages will only get new versions to patch critical bug fixes.
18
+
19
+ We'd like to offer a big thanks to the 6 contributors who made this release possible. Here are some highlights ✨:
20
+
21
+ - 📃 Add support for column grouping when exporting to Excel (#5895) @alexfauquette
22
+ - 🐞 Bugfixes
23
+
24
+ ### `@mui/x-data-grid@v5.17.2` / `@mui/x-data-grid-pro@v5.17.2` / `@mui/x-data-grid-premium@v5.17.2`
25
+
26
+ #### Changes
27
+
28
+ - [DataGrid] Revert mode if cell/row couldn't be saved due to validation error (#5897) @m4theushw
29
+ - [DataGridPremium] Export column grouping in Excel (#5895) @alexfauquette
30
+
31
+ ### `@mui/x-date-pickers@v5.0.1` / `@mui/x-date-pickers-pro@v5.0.1`
32
+
33
+ #### Changes
34
+
35
+ - [DateTimePicker] Remove circular import (#6087) @flaviendelangle
36
+ - [pickers] Add `sx` prop to the equality check of `PickersDay` (#6030) @TheUnlocked
37
+ - [pickers] Add warning when `openTo` is invalid based on available `views` (#6042) @LukasTy
38
+ - [pickers] Allow keyboard navigation to ignore disabled date for left / right arrow (#6082) @alexfauquette
39
+ - [pickers] Fix mobile picker not opening on label click (#6074) @LukasTy
40
+
41
+ ### Docs
42
+
43
+ - [docs] Add Recipes section
44
+
45
+ ### Core
46
+
47
+ - [core] Add `yarn release:tag` script (#5169) @DanailH
48
+ - [core] Upgrade monorepo (#6072) @m4theushw
49
+
50
+ ## 5.17.1
51
+
52
+ _Sep 5, 2022_
53
+
54
+ We'd like to offer a big thanks to the 3 contributors who made this release possible. Here are some highlights ✨:
55
+
56
+ - 🐞 Bugfixes
57
+
58
+ ### `@mui/x-data-grid@v5.17.1` / `@mui/x-data-grid-pro@v5.17.1` / `@mui/x-data-grid-premium@v5.17.1`
59
+
60
+ #### Changes
61
+
62
+ - [DataGrid] Fix cells being focused on mouseUp (#5980) @cherniavskii
63
+ - [DataGrid] Fix focused cell if column is spanned and new editing API is used (#5962) @m4theushw
64
+ - [DataGridPro] Fix import in lazy-loading causing a bundling error (#6031) @flaviendelangle
65
+
66
+ ## 5.17.0
67
+
68
+ _Sep 2, 2022_
69
+
70
+ 🎉 We are excited to finally introduce a stable release (v5.0.0) for the `@mui/x-date-pickers` and `@mui/x-date-pickers-pro` packages!
71
+
72
+ If you are still using picker components from the `lab`, take a look at the [migration guide](https://mui.com/x/react-date-pickers/migration-lab/).
73
+
74
+ We'd like to offer a big thanks to the 9 contributors who made this release possible. Here are some highlights ✨:
75
+
76
+ - 🎁 Implement Lazy loading (#5214) @DanailH
77
+
78
+ Pro users now can try the experimental lazy loading feature.
79
+ In a few steps, you can load your data on demand, as the rows are displayed.
80
+
81
+ To enable this feature, add `experimentalFeatures={{ lazyLoading: true }}`.
82
+ Lazy Loading requires a few other settings.
83
+ See the [documentation](https://mui.com/x/react-data-grid/row-updates/#lazy-loading) to explore the example in detail.
84
+
85
+ - 🚀 Improve `pickers` focus management (#5820) @alexfauquette
86
+ - 🎉 Enable disabling `day` on date range picker depending on `position` (#5773) @alexfauquette
87
+ - ✨ Various improvements
88
+ - 📚 Documentation improvements
89
+ - 🐞 Bugfixes
90
+
91
+ ### `@mui/x-data-grid@v5.17.0` / `@mui/x-data-grid-pro@v5.17.0` / `@mui/x-data-grid-premium@v5.17.0`
92
+
93
+ #### Changes
94
+
95
+ - [DataGrid] Add `sort` prop to columns panel slot (#5888) @gavbrennan
96
+ - [DataGrid] Do not throw if `fieldToFocus` cannot be found (#5871) @cherniavskii
97
+ - [DataGrid] Support `getRowId` in the `replaceRows` method (#5988) @flaviendelangle
98
+ - [DataGridPro] Add class name to row with open detail panel (#5924) @m4theushw
99
+ - [DataGridPro] Fix crash when using `pinnedRows` + `getRowClassName` props and `rows=[]` (#5851) @cherniavskii
100
+ - [DataGridPro] Fix filtering with inactive filter items (#5993) @alexfauquette
101
+ - [DataGridPro] Implement Lazy loading (#5214) @DanailH
102
+ - [DataGridPro] Support pinned columns and dynamic row height (#5782) @m4theushw
103
+ - [DataGridPremium] Add state initializer for column groups (#5963) @alexfauquette
104
+ - [DataGridPremium] Update grouping when `groupingValueGetter` changes (#5919) @flaviendelangle
105
+ - [DataGridPremium] Use the aggregated value on tree data real groups (#5953) @flaviendelangle
106
+
107
+ ### `@mui/x-date-pickers@v5.0.0` / `@mui/x-date-pickers-pro@v5.0.0`
108
+
109
+ #### Changes
110
+
111
+ - [DatePicker] Improve focus management (#5820) @alexfauquette
112
+ - [DateRangePicker] Enable disabling `day` depending on `position` (#5773) @alexfauquette
113
+ - [DateTimePicker] Create a new `tabs` component slot (#5972) @LukasTy
114
+ - [pickers] Do not forward validation props to the DOM on field components (#5971) @flaviendelangle
115
+ - [pickers] Do not hardcode `date-fns` elements in field components (#5975) @flaviendelangle
116
+ - [pickers] Do not require `date-fns` in `@mui/x-date-pickers-pro` (#5941) @flaviendelangle
117
+ - [pickers] Fix mobile picker not opening on label click (#5651) @LukasTy
118
+ - [pickers] Improve DOM event management on `useField` (#5901) @flaviendelangle
119
+ - [pickers] Include `community` package `themeAugmentation` in `pro` package types (#5969) @LukasTy
120
+ - [pickers] Rename `DateRangeField` into `SingleInputDateRangeField` (#5961) @flaviendelangle
121
+ - [pickers] Support `isSameError` on field components (#5984) @flaviendelangle
122
+
123
+ ### Docs
124
+
125
+ - [docs] Add `description` and `default` to pickers slots (#5893) @alexfauquette
126
+ - [docs] Fix typo (#5945) @wettopa
127
+ - [docs] Fix typo `onYearPicker` to `onYearChange` (#5954) @alexfauquette
128
+ - [docs] Update `GridCellParams`'s `value` description (#5849) @cherniavskii
129
+ - [docs] Update `README.md` to match Introduction section of the docs (#5754) @samuelsycamore
130
+
131
+ ### Core
132
+
133
+ - [core] Fix typo (#5990) @flaviendelangle
134
+ - [core] Remove old babel resolve rule (#5939) @oliviertassinari
135
+ - [core] Remove outdated TODO (#5956) @flaviendelangle
136
+ - [core] Upgrade monorepo (#5960) @cherniavskii
137
+ - [core] Fix statics (#5986) @DanailH
138
+ - [core] Remove unused dependencies (#5937) @oliviertassinari
139
+ - [license] Remove CLI (#5757) @flaviendelangle
140
+ - [test] Fix time zone sensitive test (#5955) @LukasTy
141
+ - [test] Use `userEvent.mousePress` instead of `fireClickEvent` (#5920) @cherniavskii
142
+
6
143
  ## 5.16.0
7
144
 
8
145
  _Aug 25, 2022_
@@ -585,7 +722,7 @@ We'd like to offer a big thanks to the 15 contributors who made this release pos
585
722
 
586
723
  **MonthPicker**: The prop `onMonthChange` has been removed, you can use `onChange` instead since every change is a month change
587
724
 
588
- **YearPicker**: The prop `onYearPicker` has been removed, you can use `onChange` instead since every change is a year change
725
+ **YearPicker**: The prop `onYearChange` has been removed, you can use `onChange` instead since every change is a year change
589
726
 
590
727
  **DayPicker**: The prop `isDateDisabled` has been removed, you can now use the same validation props as for the other components (`maxDate`, `minDate`, `shouldDisableDate`, `disableFuture` and `disablePast`)
591
728
 
@@ -307,6 +307,7 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
307
307
  experimentalFeatures: PropTypes.shape({
308
308
  aggregation: PropTypes.bool,
309
309
  columnGrouping: PropTypes.bool,
310
+ lazyLoading: PropTypes.bool,
310
311
  newEditingApi: PropTypes.bool,
311
312
  preventCommitWhileValidating: PropTypes.bool,
312
313
  rowPinning: PropTypes.bool,
@@ -716,6 +717,14 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
716
717
  */
717
718
  onError: PropTypes.func,
718
719
 
720
+ /**
721
+ * Callback fired when rowCount is set and the next batch of virtualized rows is rendered.
722
+ * @param {GridFetchRowsParams} params With all properties from [[GridFetchRowsParams]].
723
+ * @param {MuiEvent<{}>} event The event object.
724
+ * @param {GridCallbackDetails} details Additional details for this callback.
725
+ */
726
+ onFetchRows: PropTypes.func,
727
+
719
728
  /**
720
729
  * Callback fired when the Filter model changes before the filters are applied.
721
730
  * @param {GridFilterModel} model With all properties from [[GridFilterModel]].
@@ -980,6 +989,14 @@ process.env.NODE_ENV !== "production" ? DataGridPremiumRaw.propTypes = {
980
989
  */
981
990
  rows: PropTypes.array.isRequired,
982
991
 
992
+ /**
993
+ * Loading rows can be processed on the server or client-side.
994
+ * Set it to 'client' if you would like enable infnite loading.
995
+ * Set it to 'server' if you would like to enable lazy loading.
996
+ * * @default "client"
997
+ */
998
+ rowsLoadingMode: PropTypes.oneOf(['client', 'server']),
999
+
983
1000
  /**
984
1001
  * Sets the type of space between rows added by `getRowSpacing`.
985
1002
  * @default "margin"
@@ -1,4 +1,4 @@
1
- import { useGridInitialization, useGridInitializeState, useGridClipboard, useGridColumnMenu, useGridColumns, columnsStateInitializer, useGridDensity, useGridCsvExport, useGridPrintExport, useGridFilter, filterStateInitializer, useGridFocus, useGridKeyboardNavigation, useGridPagination, paginationStateInitializer, useGridPreferencesPanel, useGridEditing_new, useGridEditing_old, editingStateInitializer_old, editingStateInitializer_new, useGridRows, useGridRowsPreProcessors, rowsStateInitializer, useGridRowsMeta, useGridParamsApi, useGridSelection, useGridSorting, sortingStateInitializer, useGridScroll, useGridEvents, useGridDimensions, useGridStatePersistence, useGridSelectionPreProcessors, columnMenuStateInitializer, densityStateInitializer, focusStateInitializer, preferencePanelStateInitializer, rowsMetaStateInitializer, selectionStateInitializer, useGridColumnReorder, columnReorderStateInitializer, useGridColumnResize, columnResizeStateInitializer, useGridTreeData, useGridTreeDataPreProcessors, useGridColumnPinning, columnPinningStateInitializer, useGridColumnPinningPreProcessors, useGridDetailPanel, detailPanelStateInitializer, useGridDetailPanelPreProcessors, useGridInfiniteLoader, useGridColumnSpanning, useGridRowReorder, useGridRowReorderPreProcessors, useGridColumnGroupingPreProcessors, useGridRowPinning, useGridRowPinningPreProcessors, rowPinningStateInitializer, useGridColumnGrouping } from '@mui/x-data-grid-pro/internals';
1
+ import { useGridInitialization, useGridInitializeState, useGridClipboard, useGridColumnMenu, useGridColumns, columnsStateInitializer, useGridDensity, useGridCsvExport, useGridPrintExport, useGridFilter, filterStateInitializer, useGridFocus, useGridKeyboardNavigation, useGridPagination, paginationStateInitializer, useGridPreferencesPanel, useGridEditing_new, useGridEditing_old, editingStateInitializer_old, editingStateInitializer_new, useGridRows, useGridRowsPreProcessors, rowsStateInitializer, useGridRowsMeta, useGridParamsApi, useGridSelection, useGridSorting, sortingStateInitializer, useGridScroll, useGridEvents, useGridDimensions, useGridStatePersistence, useGridSelectionPreProcessors, columnMenuStateInitializer, densityStateInitializer, focusStateInitializer, preferencePanelStateInitializer, rowsMetaStateInitializer, selectionStateInitializer, useGridColumnReorder, columnReorderStateInitializer, useGridColumnResize, columnResizeStateInitializer, useGridTreeData, useGridTreeDataPreProcessors, useGridColumnPinning, columnPinningStateInitializer, useGridColumnPinningPreProcessors, useGridDetailPanel, detailPanelStateInitializer, useGridDetailPanelPreProcessors, useGridInfiniteLoader, useGridColumnSpanning, useGridRowReorder, useGridRowReorderPreProcessors, useGridColumnGroupingPreProcessors, useGridRowPinning, useGridRowPinningPreProcessors, rowPinningStateInitializer, useGridColumnGrouping, columnGroupsStateInitializer } from '@mui/x-data-grid-pro/internals';
2
2
  // Premium-only features
3
3
  import { useGridAggregation, aggregationStateInitializer } from '../hooks/features/aggregation/useGridAggregation';
4
4
  import { useGridAggregationPreProcessors } from '../hooks/features/aggregation/useGridAggregationPreProcessors';
@@ -48,6 +48,7 @@ export const useDataGridPremiumComponent = (inputApiRef, props) => {
48
48
  useGridInitializeState(paginationStateInitializer, apiRef, props);
49
49
  useGridInitializeState(rowsMetaStateInitializer, apiRef, props);
50
50
  useGridInitializeState(columnMenuStateInitializer, apiRef, props);
51
+ useGridInitializeState(columnGroupsStateInitializer, apiRef, props);
51
52
  useGridRowGrouping(apiRef, props);
52
53
  useGridTreeData(apiRef);
53
54
  useGridAggregation(apiRef, props);
@@ -23,8 +23,23 @@ const getAggregationCellValue = ({
23
23
 
24
24
  const values = [];
25
25
  rowIds.forEach(rowId => {
26
+ var _rowNode$children;
27
+
26
28
  if (aggregationRowsScope === 'filtered' && filteredRowsLookup[rowId] === false) {
27
29
  return;
30
+ } // If the row is a group, we want to aggregate based on its children
31
+ // For instance in the following tree, we want the aggregated values of A to be based on A.A, A.B.A and A.B.B but not A.B
32
+ // A
33
+ // A.A
34
+ // A.B
35
+ // A.B.A
36
+ // A.B.B
37
+
38
+
39
+ const rowNode = apiRef.current.getRowNode(rowId);
40
+
41
+ if ((_rowNode$children = rowNode.children) != null && _rowNode$children.length) {
42
+ return;
28
43
  }
29
44
 
30
45
  values.push(apiRef.current.getCellValue(rowId, field));
@@ -34,7 +34,7 @@ export declare const addFooterRows: ({ groupingParams, aggregationRules, getAggr
34
34
  /**
35
35
  * Compares two sets of aggregation rules to determine if they are equal or not.
36
36
  */
37
- export declare const hasAggregationRulesChanged: (previousValue: GridAggregationRules | undefined, newValue: GridAggregationRules) => boolean;
37
+ export declare const areAggregationRulesEqual: (previousValue: GridAggregationRules | undefined, newValue: GridAggregationRules) => boolean;
38
38
  export declare const getAggregationFunctionLabel: ({ apiRef, aggregationRule, }: {
39
39
  apiRef: React.MutableRefObject<GridApiPremium>;
40
40
  aggregationRule: GridAggregationRule;
@@ -149,27 +149,27 @@ export const addFooterRows = ({
149
149
  * Compares two sets of aggregation rules to determine if they are equal or not.
150
150
  */
151
151
 
152
- export const hasAggregationRulesChanged = (previousValue, newValue) => {
152
+ export const areAggregationRulesEqual = (previousValue, newValue) => {
153
153
  const previousFields = Object.keys(previousValue != null ? previousValue : {});
154
154
  const newFields = Object.keys(newValue);
155
155
 
156
156
  if (!isDeepEqual(previousFields, newFields)) {
157
- return true;
157
+ return false;
158
158
  }
159
159
 
160
- return newFields.some(field => {
160
+ return newFields.every(field => {
161
161
  const previousRule = previousValue == null ? void 0 : previousValue[field];
162
162
  const newRule = newValue[field];
163
163
 
164
164
  if ((previousRule == null ? void 0 : previousRule.aggregationFunction) !== (newRule == null ? void 0 : newRule.aggregationFunction)) {
165
- return true;
165
+ return false;
166
166
  }
167
167
 
168
168
  if ((previousRule == null ? void 0 : previousRule.aggregationFunctionName) !== (newRule == null ? void 0 : newRule.aggregationFunctionName)) {
169
- return true;
169
+ return false;
170
170
  }
171
171
 
172
- return false;
172
+ return true;
173
173
  });
174
174
  };
175
175
  export const getAggregationFunctionLabel = ({
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import { gridColumnLookupSelector, useGridApiEventHandler, useGridApiMethod } from '@mui/x-data-grid-pro';
4
4
  import { gridAggregationModelSelector } from './gridAggregationSelectors';
5
- import { getAggregationRules, mergeStateWithAggregationModel, hasAggregationRulesChanged } from './gridAggregationUtils';
5
+ import { getAggregationRules, mergeStateWithAggregationModel, areAggregationRulesEqual } from './gridAggregationUtils';
6
6
  import { createAggregationLookup } from './createAggregationLookup';
7
7
  export const aggregationStateInitializer = (state, props, apiRef) => {
8
8
  var _ref, _props$aggregationMod, _props$initialState, _props$initialState$a;
@@ -69,13 +69,13 @@ export const useGridAggregation = (apiRef, props) => {
69
69
  aggregationFunctions: props.aggregationFunctions
70
70
  }); // Re-apply the row hydration to add / remove the aggregation footers
71
71
 
72
- if (hasAggregationRulesChanged(rulesOnLastRowHydration, aggregationRules)) {
72
+ if (!areAggregationRulesEqual(rulesOnLastRowHydration, aggregationRules)) {
73
73
  apiRef.current.unstable_requestPipeProcessorsApplication('hydrateRows');
74
74
  applyAggregation();
75
75
  } // Re-apply the column hydration to wrap / unwrap the aggregated columns
76
76
 
77
77
 
78
- if (hasAggregationRulesChanged(rulesOnLastColumnHydration, aggregationRules)) {
78
+ if (!areAggregationRulesEqual(rulesOnLastColumnHydration, aggregationRules)) {
79
79
  apiRef.current.unstable_requestPipeProcessorsApplication('hydrateColumns');
80
80
  }
81
81
  }, [apiRef, applyAggregation, props.aggregationFunctions, props.disableAggregation]);
@@ -161,11 +161,12 @@ export const wrapColumnWithAggregationValue = ({
161
161
  aggregationRule
162
162
  }) => {
163
163
  const getCellAggregationResult = (id, field) => {
164
- var _parent, _gridAggregationLooku;
164
+ var _rowNode$children, _rowNode$parent, _gridAggregationLooku;
165
165
 
166
166
  let cellAggregationPosition = null;
167
+ const rowNode = apiRef.current.getRowNode(id);
167
168
 
168
- if (id.toString().startsWith('auto-generated-row-')) {
169
+ if ((_rowNode$children = rowNode.children) != null && _rowNode$children.length) {
169
170
  cellAggregationPosition = 'inline';
170
171
  } else if (id.toString().startsWith('auto-generated-group-footer-')) {
171
172
  cellAggregationPosition = 'footer';
@@ -176,7 +177,7 @@ export const wrapColumnWithAggregationValue = ({
176
177
  } // TODO: Add custom root id
177
178
 
178
179
 
179
- const groupId = cellAggregationPosition === 'inline' ? id : (_parent = apiRef.current.getRowNode(id).parent) != null ? _parent : '';
180
+ const groupId = cellAggregationPosition === 'inline' ? id : (_rowNode$parent = rowNode.parent) != null ? _rowNode$parent : '';
180
181
  const aggregationResult = (_gridAggregationLooku = gridAggregationLookupSelector(apiRef)[groupId]) == null ? void 0 : _gridAggregationLooku[field];
181
182
 
182
183
  if (!aggregationResult || aggregationResult.position !== cellAggregationPosition) {
@@ -34,6 +34,11 @@ export interface GridExcelExportOptions extends GridFileExportOptions {
34
34
  * Object mapping column field to Exceljs style
35
35
  * */
36
36
  columnsStyles?: ColumnsStylesInterface;
37
+ /**
38
+ * If `true`, the headers of the column groups will be added into the file.
39
+ * @default true
40
+ */
41
+ includeColumnGroupsHeaders?: boolean;
37
42
  }
38
43
  export interface GridToolbarExportProps extends GridToolbarExportPropsCommunity {
39
44
  excelOptions: GridExcelExportOptions & GridExportDisplayOptions;
@@ -5,6 +5,7 @@ interface BuildExcelOptions {
5
5
  columns: GridStateColDef[];
6
6
  rowIds: GridRowId[];
7
7
  includeHeaders: boolean;
8
+ includeColumnGroupsHeaders: boolean;
8
9
  valueOptionsSheetName: string;
9
10
  exceljsPreProcess?: (processInput: GridExceljsProcessInput) => Promise<void>;
10
11
  exceljsPostProcess?: (processInput: GridExceljsProcessInput) => Promise<void>;
@@ -174,11 +174,79 @@ const serializeColumn = (column, columnsStyles) => {
174
174
  };
175
175
  };
176
176
 
177
+ const addColumnGroupingHeaders = (worksheet, columns, api) => {
178
+ const maxDepth = Math.max(...columns.map(({
179
+ field
180
+ }) => {
181
+ var _api$unstable_getColu, _api$unstable_getColu2;
182
+
183
+ return (_api$unstable_getColu = (_api$unstable_getColu2 = api.unstable_getColumnGroupPath(field)) == null ? void 0 : _api$unstable_getColu2.length) != null ? _api$unstable_getColu : 0;
184
+ }));
185
+
186
+ if (maxDepth === 0) {
187
+ return;
188
+ }
189
+
190
+ const columnGroupDetails = api.unstable_getAllGroupDetails();
191
+
192
+ for (let rowIndex = 0; rowIndex < maxDepth; rowIndex += 1) {
193
+ const row = columns.map(({
194
+ field
195
+ }) => {
196
+ const groupingPath = api.unstable_getColumnGroupPath(field);
197
+
198
+ if (groupingPath.length <= rowIndex) {
199
+ return {
200
+ groupId: null,
201
+ parents: groupingPath
202
+ };
203
+ }
204
+
205
+ return _extends({}, columnGroupDetails[groupingPath[rowIndex]], {
206
+ parents: groupingPath.slice(0, rowIndex)
207
+ });
208
+ });
209
+ const newRow = worksheet.addRow(row.map(group => group.groupId === null ? null : (group == null ? void 0 : group.headerName) || group.groupId)); // use `rowCount`, since worksheet can have additional rows added in `exceljsPreProcess`
210
+
211
+ const lastRowIndex = newRow.worksheet.rowCount;
212
+ let leftIndex = 0;
213
+ let rightIndex = 1;
214
+
215
+ while (rightIndex < columns.length) {
216
+ const {
217
+ groupId: leftGroupId,
218
+ parents: leftParents
219
+ } = row[leftIndex];
220
+ const {
221
+ groupId: rightGroupId,
222
+ parents: rightParents
223
+ } = row[rightIndex];
224
+ const areInSameGroup = leftGroupId === rightGroupId && leftParents.length === rightParents.length && leftParents.every((leftParent, index) => rightParents[index] === leftParent);
225
+
226
+ if (areInSameGroup) {
227
+ rightIndex += 1;
228
+ } else {
229
+ if (rightIndex - leftIndex > 1) {
230
+ worksheet.mergeCells(lastRowIndex, leftIndex + 1, lastRowIndex, rightIndex);
231
+ }
232
+
233
+ leftIndex = rightIndex;
234
+ rightIndex += 1;
235
+ }
236
+ }
237
+
238
+ if (rightIndex - leftIndex > 1) {
239
+ worksheet.mergeCells(lastRowIndex, leftIndex + 1, lastRowIndex, rightIndex);
240
+ }
241
+ }
242
+ };
243
+
177
244
  export async function buildExcel(options, api) {
178
245
  const {
179
246
  columns,
180
247
  rowIds,
181
248
  includeHeaders,
249
+ includeColumnGroupsHeaders,
182
250
  valueOptionsSheetName,
183
251
  exceljsPreProcess,
184
252
  exceljsPostProcess,
@@ -196,6 +264,10 @@ export async function buildExcel(options, api) {
196
264
  });
197
265
  }
198
266
 
267
+ if (includeColumnGroupsHeaders) {
268
+ addColumnGroupingHeaders(worksheet, columns, api);
269
+ }
270
+
199
271
  if (includeHeaders) {
200
272
  worksheet.addRow(columns.map(column => column.headerName || column.field));
201
273
  }
@@ -15,7 +15,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
15
15
  export const useGridExcelExport = apiRef => {
16
16
  const logger = useGridLogger(apiRef, 'useGridExcelExport');
17
17
  const getDataAsExcel = React.useCallback((options = {}) => {
18
- var _options$getRowsToExp, _options$includeHeade;
18
+ var _options$getRowsToExp, _options$includeHeade, _options$includeColum;
19
19
 
20
20
  logger.debug(`Get data as excel`);
21
21
  const getRowsToExport = (_options$getRowsToExp = options.getRowsToExport) != null ? _options$getRowsToExp : defaultGetRowsToExport;
@@ -30,6 +30,7 @@ export const useGridExcelExport = apiRef => {
30
30
  columns: exportedColumns,
31
31
  rowIds: exportedRowIds,
32
32
  includeHeaders: (_options$includeHeade = options.includeHeaders) != null ? _options$includeHeade : true,
33
+ includeColumnGroupsHeaders: (_options$includeColum = options.includeColumnGroupsHeaders) != null ? _options$includeColum : true,
33
34
  valueOptionsSheetName: (options == null ? void 0 : options.valueOptionsSheetName) || 'Options',
34
35
  columnsStyles: options == null ? void 0 : options.columnsStyles,
35
36
  exceljsPreProcess: options == null ? void 0 : options.exceljsPreProcess,
@@ -1,3 +1,4 @@
1
+ import { GridColDef } from '@mui/x-data-grid';
1
2
  export declare type GridRowGroupingModel = string[];
2
3
  export interface GridRowGroupingState {
3
4
  model: GridRowGroupingModel;
@@ -10,7 +11,7 @@ export interface GridRowGroupingInternalCache {
10
11
  * Tracks the model on the last pre-processing
11
12
  * Allows to check if we need to re-build the grouping columns when the grid upserts a column.
12
13
  */
13
- sanitizedModelOnLastRowTreeCreation: GridRowGroupingModel;
14
+ rulesOnLastRowTreeCreation: GridGroupingRules;
14
15
  }
15
16
  export interface GridRowGroupingApi {
16
17
  /**
@@ -36,3 +37,8 @@ export interface GridRowGroupingApi {
36
37
  */
37
38
  setRowGroupingCriteriaIndex: (groupingCriteriaField: string, groupingIndex: number) => void;
38
39
  }
40
+ export interface GridGroupingRule<R = any, V = any> {
41
+ field: string;
42
+ groupingValueGetter?: GridColDef<R, V>['groupingValueGetter'];
43
+ }
44
+ export declare type GridGroupingRules<R = any> = GridGroupingRule<R>[];
@@ -1,8 +1,8 @@
1
1
  import * as React from 'react';
2
2
  import { GridRowTreeConfig, GridFilterState, GridFilterModel } from '@mui/x-data-grid-pro';
3
- import { GridAggregatedFilterItemApplier } from '@mui/x-data-grid-pro/internals';
3
+ import { GridAggregatedFilterItemApplier, GridColumnRawLookup, GridApiCommunity } from '@mui/x-data-grid-pro/internals';
4
4
  import { DataGridPremiumProcessedProps } from '../../../models/dataGridPremiumProps';
5
- import { GridRowGroupingModel } from './gridRowGroupingInterfaces';
5
+ import { GridGroupingRules, GridRowGroupingModel } from './gridRowGroupingInterfaces';
6
6
  import { GridStatePremium } from '../../../models/gridStatePremium';
7
7
  import { GridApiPremium } from '../../../models/gridApiPremium';
8
8
  export declare const GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD = "__row_group_by_columns_group__";
@@ -14,6 +14,7 @@ interface FilterRowTreeFromTreeDataParams {
14
14
  rowTree: GridRowTreeConfig;
15
15
  isRowMatchingFilters: GridAggregatedFilterItemApplier | null;
16
16
  filterModel: GridFilterModel;
17
+ apiRef: React.MutableRefObject<GridApiCommunity>;
17
18
  }
18
19
  /**
19
20
  * A leaf is visible if it passed the filter
@@ -25,4 +26,12 @@ export declare const filterRowTreeFromGroupingColumns: (params: FilterRowTreeFro
25
26
  export declare const getColDefOverrides: (groupingColDefProp: DataGridPremiumProcessedProps['groupingColDef'], fields: string[]) => import("@mui/x-data-grid-pro").GridGroupingColDefOverride<any> | null | undefined;
26
27
  export declare const mergeStateWithRowGroupingModel: (rowGroupingModel: GridRowGroupingModel) => (state: GridStatePremium) => GridStatePremium;
27
28
  export declare const setStrategyAvailability: (apiRef: React.MutableRefObject<GridApiPremium>, disableRowGrouping: boolean) => void;
29
+ export declare const getGroupingRules: ({ sanitizedRowGroupingModel, columnsLookup, }: {
30
+ sanitizedRowGroupingModel: GridRowGroupingModel;
31
+ columnsLookup: GridColumnRawLookup;
32
+ }) => GridGroupingRules<any>;
33
+ /**
34
+ * Compares two sets of grouping rules to determine if they are equal or not.
35
+ */
36
+ export declare const areGroupingRulesEqual: (previousValue: GridGroupingRules | undefined, newValue: GridGroupingRules<any>) => boolean;
28
37
  export {};
@@ -81,7 +81,7 @@ export const filterRowTreeFromGroupingColumns = params => {
81
81
  isPassingFiltering = filteredDescendantCount > 0;
82
82
  } else {
83
83
  const allResults = [...ancestorsResults, filterResults];
84
- isPassingFiltering = passFilterLogic(allResults.map(result => result.passingFilterItems), allResults.map(result => result.passingQuickFilterValues), filterModel);
84
+ isPassingFiltering = passFilterLogic(allResults.map(result => result.passingFilterItems), allResults.map(result => result.passingQuickFilterValues), filterModel, params.apiRef);
85
85
  }
86
86
  }
87
87
 
@@ -149,4 +149,38 @@ export const setStrategyAvailability = (apiRef, disableRowGrouping) => {
149
149
  }
150
150
 
151
151
  apiRef.current.unstable_setStrategyAvailability('rowTree', ROW_GROUPING_STRATEGY, isAvailable);
152
+ };
153
+ export const getGroupingRules = ({
154
+ sanitizedRowGroupingModel,
155
+ columnsLookup
156
+ }) => sanitizedRowGroupingModel.map(field => {
157
+ var _columnsLookup$field;
158
+
159
+ return {
160
+ field,
161
+ groupingValueGetter: (_columnsLookup$field = columnsLookup[field]) == null ? void 0 : _columnsLookup$field.groupingValueGetter
162
+ };
163
+ });
164
+ /**
165
+ * Compares two sets of grouping rules to determine if they are equal or not.
166
+ */
167
+
168
+ export const areGroupingRulesEqual = (previousValue = [], newValue) => {
169
+ if (previousValue.length !== newValue.length) {
170
+ return false;
171
+ }
172
+
173
+ return newValue.every((newRule, newRuleIndex) => {
174
+ const previousRule = previousValue[newRuleIndex];
175
+
176
+ if (previousRule.groupingValueGetter !== newRule.groupingValueGetter) {
177
+ return false;
178
+ }
179
+
180
+ if (previousRule.field !== newRule.field) {
181
+ return false;
182
+ }
183
+
184
+ return true;
185
+ });
152
186
  };
@@ -1,10 +1,10 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
3
  import MuiDivider from '@mui/material/Divider';
4
- import { useGridApiEventHandler, useGridApiMethod, gridFilteredDescendantCountLookupSelector } from '@mui/x-data-grid-pro';
5
- import { useGridRegisterPipeProcessor, isDeepEqual } from '@mui/x-data-grid-pro/internals';
4
+ import { useGridApiEventHandler, useGridApiMethod, gridFilteredDescendantCountLookupSelector, gridColumnLookupSelector } from '@mui/x-data-grid-pro';
5
+ import { useGridRegisterPipeProcessor } from '@mui/x-data-grid-pro/internals';
6
6
  import { gridRowGroupingModelSelector, gridRowGroupingSanitizedModelSelector } from './gridRowGroupingSelector';
7
- import { getRowGroupingFieldFromGroupingCriteria, ROW_GROUPING_STRATEGY, isGroupingColumn, mergeStateWithRowGroupingModel, setStrategyAvailability } from './gridRowGroupingUtils';
7
+ import { getRowGroupingFieldFromGroupingCriteria, ROW_GROUPING_STRATEGY, isGroupingColumn, mergeStateWithRowGroupingModel, setStrategyAvailability, getGroupingRules, areGroupingRulesEqual } from './gridRowGroupingUtils';
8
8
  import { GridRowGroupableColumnMenuItems } from '../../../components/GridRowGroupableColumnMenuItems';
9
9
  import { GridRowGroupingColumnMenuItems } from '../../../components/GridRowGroupingColumnMenuItems';
10
10
  import { jsx as _jsx } from "react/jsx-runtime";
@@ -17,7 +17,7 @@ export const rowGroupingStateInitializer = (state, props, apiRef) => {
17
17
  var _ref, _props$rowGroupingMod, _props$initialState, _props$initialState$r;
18
18
 
19
19
  apiRef.current.unstable_caches.rowGrouping = {
20
- sanitizedModelOnLastRowTreeCreation: []
20
+ rulesOnLastRowTreeCreation: []
21
21
  };
22
22
  return _extends({}, state, {
23
23
  rowGrouping: {
@@ -179,11 +179,15 @@ export const useGridRowGrouping = (apiRef, props) => {
179
179
  }
180
180
  }, [apiRef, props.rowGroupingColumnMode]);
181
181
  const checkGroupingColumnsModelDiff = React.useCallback(() => {
182
- const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
183
- const lastGroupingColumnsModelApplied = apiRef.current.unstable_caches.rowGrouping.sanitizedModelOnLastRowTreeCreation;
182
+ const sanitizedRowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
183
+ const rulesOnLastRowTreeCreation = apiRef.current.unstable_caches.rowGrouping.rulesOnLastRowTreeCreation;
184
+ const groupingRules = getGroupingRules({
185
+ sanitizedRowGroupingModel,
186
+ columnsLookup: gridColumnLookupSelector(apiRef)
187
+ });
184
188
 
185
- if (!isDeepEqual(lastGroupingColumnsModelApplied, rowGroupingModel)) {
186
- apiRef.current.unstable_caches.rowGrouping.sanitizedModelOnLastRowTreeCreation = rowGroupingModel;
189
+ if (!areGroupingRulesEqual(rulesOnLastRowTreeCreation, groupingRules)) {
190
+ apiRef.current.unstable_caches.rowGrouping.rulesOnLastRowTreeCreation = groupingRules;
187
191
  apiRef.current.unstable_requestPipeProcessorsApplication('hydrateColumns');
188
192
  setStrategyAvailability(apiRef, props.disableRowGrouping); // Refresh the row tree creation strategy processing
189
193
  // TODO: Add a clean way to re-run a strategy processing without publishing a private event