@mui/x-data-grid-premium 8.7.0 → 8.9.0

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 (40) hide show
  1. package/CHANGELOG.md +199 -24
  2. package/DataGridPremium/DataGridPremium.js +1 -1
  3. package/DataGridPremium/useDataGridPremiumComponent.js +19 -7
  4. package/DataGridPremium/useDataGridPremiumProps.js +2 -1
  5. package/esm/DataGridPremium/DataGridPremium.js +1 -1
  6. package/esm/DataGridPremium/useDataGridPremiumComponent.js +21 -8
  7. package/esm/DataGridPremium/useDataGridPremiumProps.js +2 -1
  8. package/esm/hooks/features/aggregation/createAggregationLookup.d.ts +9 -4
  9. package/esm/hooks/features/aggregation/createAggregationLookup.js +78 -41
  10. package/esm/hooks/features/aggregation/gridAggregationFunctions.js +2 -2
  11. package/esm/hooks/features/aggregation/gridAggregationInterfaces.d.ts +13 -1
  12. package/esm/hooks/features/aggregation/gridAggregationUtils.d.ts +2 -1
  13. package/esm/hooks/features/aggregation/gridAggregationUtils.js +2 -1
  14. package/esm/hooks/features/aggregation/useGridAggregation.js +94 -18
  15. package/esm/hooks/features/pivoting/gridPivotingInterfaces.d.ts +12 -2
  16. package/esm/hooks/features/pivoting/useGridPivoting.d.ts +2 -1
  17. package/esm/hooks/features/pivoting/useGridPivoting.js +57 -35
  18. package/esm/hooks/features/pivoting/utils.d.ts +3 -1
  19. package/esm/hooks/features/pivoting/utils.js +22 -14
  20. package/esm/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
  21. package/esm/hooks/features/rowGrouping/useGridDataSourceRowGroupingPreProcessors.js +2 -2
  22. package/esm/index.js +3 -3
  23. package/esm/typeOverloads/modules.d.ts +2 -1
  24. package/hooks/features/aggregation/createAggregationLookup.d.ts +9 -4
  25. package/hooks/features/aggregation/createAggregationLookup.js +79 -41
  26. package/hooks/features/aggregation/gridAggregationFunctions.js +2 -2
  27. package/hooks/features/aggregation/gridAggregationInterfaces.d.ts +13 -1
  28. package/hooks/features/aggregation/gridAggregationUtils.d.ts +2 -1
  29. package/hooks/features/aggregation/gridAggregationUtils.js +4 -2
  30. package/hooks/features/aggregation/useGridAggregation.js +92 -16
  31. package/hooks/features/pivoting/gridPivotingInterfaces.d.ts +12 -2
  32. package/hooks/features/pivoting/useGridPivoting.d.ts +2 -1
  33. package/hooks/features/pivoting/useGridPivoting.js +60 -37
  34. package/hooks/features/pivoting/utils.d.ts +3 -1
  35. package/hooks/features/pivoting/utils.js +22 -14
  36. package/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
  37. package/hooks/features/rowGrouping/useGridDataSourceRowGroupingPreProcessors.js +1 -1
  38. package/index.js +3 -3
  39. package/package.json +6 -6
  40. package/typeOverloads/modules.d.ts +2 -1
@@ -2,6 +2,7 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import { isLeaf, gridStringOrNumberComparator } from '@mui/x-data-grid-pro';
3
3
  import { getDefaultColTypeDef } from '@mui/x-data-grid-pro/internals';
4
4
  import { isGroupingColumn } from "../rowGrouping/index.js";
5
+ import { defaultGetAggregationPosition } from "../aggregation/gridAggregationUtils.js";
5
6
  const columnGroupIdSeparator = '>->';
6
7
  export const isPivotingAvailable = props => {
7
8
  return !props.disablePivoting;
@@ -64,7 +65,8 @@ export const getPivotedData = ({
64
65
  columns,
65
66
  pivotModel,
66
67
  apiRef,
67
- pivotingColDef
68
+ pivotingColDef,
69
+ groupingColDef
68
70
  }) => {
69
71
  const visibleColumns = pivotModel.columns.filter(column => !column.hidden);
70
72
  const visibleRows = pivotModel.rows.filter(row => !row.hidden);
@@ -129,26 +131,31 @@ export const getPivotedData = ({
129
131
  const row = rows[i];
130
132
  const newRow = _extends({}, row);
131
133
  const columnGroupPath = [];
132
- visibleColumns.forEach(({
133
- field: colGroupField
134
- }, depth) => {
134
+ for (let j = 0; j < visibleColumns.length; j += 1) {
135
+ const {
136
+ field: colGroupField
137
+ } = visibleColumns[j];
138
+ const depth = j;
135
139
  const column = initialColumns.get(colGroupField);
136
140
  if (!column) {
137
- return;
141
+ continue;
138
142
  }
139
143
  let colValue = apiRef.current.getRowValue(row, column) ?? '(No value)';
144
+ if (column.type !== 'number') {
145
+ colValue = String(colValue);
146
+ }
140
147
  if (column.type === 'singleSelect') {
141
148
  const singleSelectColumn = column;
142
149
  if (singleSelectColumn.getOptionLabel) {
143
150
  colValue = singleSelectColumn.getOptionLabel(colValue);
144
151
  }
145
152
  }
146
- columnGroupPath.push(String(colValue));
153
+ columnGroupPath.push(colValue);
147
154
  const groupId = columnGroupPath.join(columnGroupIdSeparator);
148
155
  if (!columnGroupingModelLookup.has(groupId)) {
149
156
  const columnGroup = {
150
157
  groupId,
151
- headerName: String(colValue),
158
+ headerName: colValue,
152
159
  children: []
153
160
  };
154
161
  columnGroupingModelLookup.set(groupId, columnGroup);
@@ -174,7 +181,7 @@ export const getPivotedData = ({
174
181
  newRow[valueKey] = apiRef.current.getRowValue(row, originalColumn);
175
182
  });
176
183
  }
177
- });
184
+ }
178
185
  newRows.push(newRow);
179
186
  }
180
187
  sortColumnGroups(columnGroupingModel, visibleColumns);
@@ -239,19 +246,20 @@ export const getPivotedData = ({
239
246
  }
240
247
  }
241
248
  createColumns(columnGroupingModel);
249
+ const groupingColDefOverrides = params => _extends({}, typeof groupingColDef === 'function' ? groupingColDef(params) : groupingColDef || {}, {
250
+ filterable: false,
251
+ aggregable: false,
252
+ hideable: false
253
+ });
242
254
  return {
243
255
  rows: visibleRows.length > 0 ? newRows : [],
244
256
  columns: pivotColumns,
245
257
  rowGroupingModel: visibleRows.map(row => row.field),
246
258
  aggregationModel,
247
- getAggregationPosition: groupNode => groupNode.depth === -1 ? 'footer' : 'inline',
259
+ getAggregationPosition: defaultGetAggregationPosition,
248
260
  columnVisibilityModel,
249
261
  columnGroupingModel,
250
- groupingColDef: {
251
- filterable: false,
252
- aggregable: false,
253
- hideable: false
254
- },
262
+ groupingColDef: groupingColDefOverrides,
255
263
  headerFilters: false,
256
264
  disableAggregation: false,
257
265
  disableRowGrouping: false
@@ -116,6 +116,11 @@ export const mergeStateWithRowGroupingModel = rowGroupingModel => state => _exte
116
116
  })
117
117
  });
118
118
  export const setStrategyAvailability = (privateApiRef, disableRowGrouping, dataSource) => {
119
+ const strategy = dataSource ? RowGroupingStrategy.DataSource : RowGroupingStrategy.Default;
120
+ if (privateApiRef.current.getActiveStrategy(GridStrategyGroup.RowTree) === strategy) {
121
+ // If the strategy is already active, we don't need to set it again
122
+ return;
123
+ }
119
124
  let isAvailable;
120
125
  if (disableRowGrouping) {
121
126
  isAvailable = () => false;
@@ -125,7 +130,6 @@ export const setStrategyAvailability = (privateApiRef, disableRowGrouping, dataS
125
130
  return rowGroupingSanitizedModel.length > 0;
126
131
  };
127
132
  }
128
- const strategy = dataSource ? RowGroupingStrategy.DataSource : RowGroupingStrategy.Default;
129
133
  privateApiRef.current.setStrategyAvailability(GridStrategyGroup.RowTree, strategy, isAvailable);
130
134
  };
131
135
  export const getCellGroupingCriteria = ({
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { gridRowTreeSelector, gridColumnLookupSelector } from '@mui/x-data-grid-pro';
3
- import { useGridRegisterStrategyProcessor, createRowTree, updateRowTree, getVisibleRowsLookup, skipSorting, skipFiltering } from '@mui/x-data-grid-pro/internals';
3
+ import { useGridRegisterStrategyProcessor, createRowTree, updateRowTree, getVisibleRowsLookup, skipSorting, skipFiltering, getParentPath } from '@mui/x-data-grid-pro/internals';
4
4
  import { getGroupingRules, RowGroupingStrategy } from "./gridRowGroupingUtils.js";
5
5
  import { gridRowGroupingSanitizedModelSelector } from "./gridRowGroupingSelector.js";
6
6
  export const useGridDataSourceRowGroupingPreProcessors = (apiRef, props) => {
@@ -21,7 +21,7 @@ export const useGridDataSourceRowGroupingPreProcessors = (apiRef, props) => {
21
21
  });
22
22
  apiRef.current.caches.rowGrouping.rulesOnLastRowTreeCreation = groupingRules;
23
23
  const getRowTreeBuilderNode = rowId => {
24
- const parentPath = params.updates.groupKeys ?? [];
24
+ const parentPath = params.updates.groupKeys ?? getParentPath(rowId, params);
25
25
  const leafKey = getGroupKey(params.dataRowIdToModelLookup[rowId]);
26
26
  return {
27
27
  id: rowId,
package/esm/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * @mui/x-data-grid-premium v8.7.0
2
+ * @mui/x-data-grid-premium v8.9.0
3
3
  *
4
- * @license MUI X Commercial
5
- * This source code is licensed under the commercial license found in the
4
+ * @license SEE LICENSE IN LICENSE
5
+ * This source code is licensed under the SEE LICENSE IN LICENSE license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  import "./typeOverloads/index.js";
@@ -5,7 +5,7 @@ import type { GridRowGroupingModel, GridAggregationModel, GridAggregationCellMet
5
5
  import { GridRowGroupingInternalCache } from "../hooks/features/rowGrouping/gridRowGroupingInterfaces.js";
6
6
  import { GridAggregationInternalCache } from "../hooks/features/aggregation/gridAggregationInterfaces.js";
7
7
  import type { GridExcelExportOptions } from "../hooks/features/export/gridExcelExportInterface.js";
8
- import type { GridPivotModel } from "../hooks/features/pivoting/gridPivotingInterfaces.js";
8
+ import type { GridPivotingInternalCache, GridPivotModel } from "../hooks/features/pivoting/gridPivotingInterfaces.js";
9
9
  export interface GridControlledStateEventLookupPremium {
10
10
  /**
11
11
  * Fired when the aggregation model changes.
@@ -105,6 +105,7 @@ export interface GridColumnHeaderParamsPremium<R extends GridValidRowModel = any
105
105
  aggregation?: GridAggregationHeaderMeta;
106
106
  }
107
107
  export interface GridApiCachesPremium extends GridApiCachesPro {
108
+ pivoting: GridPivotingInternalCache;
108
109
  rowGrouping: GridRowGroupingInternalCache;
109
110
  aggregation: GridAggregationInternalCache;
110
111
  }
@@ -1,17 +1,22 @@
1
1
  import { RefObject } from '@mui/x-internals/types';
2
2
  import { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
3
3
  import { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
4
- import { GridAggregationFunction, GridAggregationFunctionDataSource, GridAggregationLookup } from "./gridAggregationInterfaces.js";
4
+ import { GridAggregationLookup, GridAggregationRules } from "./gridAggregationInterfaces.js";
5
+ export declare const shouldApplySorting: (aggregationRules: GridAggregationRules, aggregatedFields: string[]) => boolean;
5
6
  export declare const createAggregationLookup: ({
6
7
  apiRef,
7
- aggregationFunctions,
8
+ aggregationRules,
9
+ aggregatedFields,
8
10
  aggregationRowsScope,
9
11
  getAggregationPosition,
10
- isDataSource
12
+ isDataSource,
13
+ applySorting
11
14
  }: {
12
15
  apiRef: RefObject<GridPrivateApiPremium>;
13
- aggregationFunctions: Record<string, GridAggregationFunction> | Record<string, GridAggregationFunctionDataSource>;
16
+ aggregationRules: GridAggregationRules;
17
+ aggregatedFields: string[];
14
18
  aggregationRowsScope: DataGridPremiumProcessedProps["aggregationRowsScope"];
15
19
  getAggregationPosition: DataGridPremiumProcessedProps["getAggregationPosition"];
16
20
  isDataSource: boolean;
21
+ applySorting: boolean;
17
22
  }) => GridAggregationLookup;
@@ -3,55 +3,72 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.createAggregationLookup = void 0;
6
+ exports.shouldApplySorting = exports.createAggregationLookup = void 0;
7
7
  var _xDataGridPro = require("@mui/x-data-grid-pro");
8
- var _gridAggregationUtils = require("./gridAggregationUtils");
9
- var _gridAggregationSelectors = require("./gridAggregationSelectors");
10
- const getGroupAggregatedValue = (groupId, apiRef, aggregationRowsScope, aggregatedFields, aggregationRules, position) => {
8
+ var _internals = require("@mui/x-data-grid/internals");
9
+ const shouldApplySorting = (aggregationRules, aggregatedFields) => {
10
+ return aggregatedFields.some(field => aggregationRules[field].aggregationFunction.applySorting);
11
+ };
12
+ exports.shouldApplySorting = shouldApplySorting;
13
+ const getGroupAggregatedValue = (groupId, apiRef, aggregationRowsScope, aggregatedFields, aggregationRules, position, applySorting, valueGetters, publicApi, groupAggregatedValuesLookup) => {
11
14
  const groupAggregationLookup = {};
12
15
  const aggregatedValues = [];
16
+ for (let i = 0; i < aggregatedFields.length; i += 1) {
17
+ aggregatedValues[i] = {
18
+ aggregatedField: aggregatedFields[i],
19
+ values: []
20
+ };
21
+ }
22
+ const rowTree = (0, _xDataGridPro.gridRowTreeSelector)(apiRef);
23
+ const rowLookup = (0, _xDataGridPro.gridRowsLookupSelector)(apiRef);
24
+ const isPivotActive = apiRef.current.state.pivoting.active;
13
25
  const rowIds = apiRef.current.getRowGroupChildren({
14
- groupId
26
+ groupId,
27
+ applySorting,
28
+ directChildrenOnly: true,
29
+ skipAutoGeneratedRows: false,
30
+ applyFiltering: aggregationRowsScope === 'filtered'
15
31
  });
16
- const filteredRowsLookup = (0, _xDataGridPro.gridFilteredRowsLookupSelector)(apiRef);
17
- rowIds.forEach(rowId => {
18
- if (aggregationRowsScope === 'filtered' && filteredRowsLookup[rowId] === false) {
19
- return;
20
- }
21
-
22
- // If the row is a group, we want to aggregate based on its children
23
- // 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
24
- // A
25
- // A.A
26
- // A.B
27
- // A.B.A
28
- // A.B.B
29
- const rowNode = (0, _xDataGridPro.gridRowNodeSelector)(apiRef, rowId);
32
+ for (let i = 0; i < rowIds.length; i += 1) {
33
+ const rowId = rowIds[i];
34
+ const rowNode = rowTree[rowId];
30
35
  if (rowNode.type === 'group') {
31
- return;
36
+ // MERGE EXISTING VALUES FROM THE LOOKUP TABLE
37
+ const childGroupValues = groupAggregatedValuesLookup.get(rowId);
38
+ if (childGroupValues) {
39
+ for (let j = 0; j < aggregatedFields.length; j += 1) {
40
+ aggregatedValues[j].values = aggregatedValues[j].values.concat(childGroupValues[j].values);
41
+ }
42
+ }
43
+ continue;
32
44
  }
33
- const row = apiRef.current.getRow(rowId);
45
+ const row = rowLookup[rowId];
34
46
  for (let j = 0; j < aggregatedFields.length; j += 1) {
35
47
  const aggregatedField = aggregatedFields[j];
36
48
  const columnAggregationRules = aggregationRules[aggregatedField];
37
49
  const aggregationFunction = columnAggregationRules.aggregationFunction;
38
50
  const field = aggregatedField;
39
- if (aggregatedValues[j] === undefined) {
40
- aggregatedValues[j] = {
41
- aggregatedField,
42
- values: []
43
- };
44
- }
51
+ let value;
45
52
  if (typeof aggregationFunction.getCellValue === 'function') {
46
- aggregatedValues[j].values.push(aggregationFunction.getCellValue({
53
+ value = aggregationFunction.getCellValue({
54
+ field,
47
55
  row
48
- }));
56
+ });
57
+ } else if (isPivotActive) {
58
+ // Since we know that pivoted fields are flat, we can use the row directly, and save lots of processing time
59
+ value = row[field];
49
60
  } else {
50
- const colDef = apiRef.current.getColumn(field);
51
- aggregatedValues[j].values.push(apiRef.current.getRowValue(row, colDef));
61
+ if (!row) {
62
+ continue;
63
+ }
64
+ const valueGetter = valueGetters[aggregatedField];
65
+ value = valueGetter(row);
66
+ }
67
+ if (value !== undefined) {
68
+ aggregatedValues[j].values.push(value);
52
69
  }
53
70
  }
54
- });
71
+ }
55
72
  for (let i = 0; i < aggregatedValues.length; i += 1) {
56
73
  const {
57
74
  aggregatedField,
@@ -62,13 +79,16 @@ const getGroupAggregatedValue = (groupId, apiRef, aggregationRowsScope, aggregat
62
79
  values,
63
80
  groupId,
64
81
  field: aggregatedField // Added per user request in https://github.com/mui/mui-x/issues/6995#issuecomment-1327423455
65
- });
82
+ }, publicApi);
66
83
  groupAggregationLookup[aggregatedField] = {
67
84
  position,
68
85
  value
69
86
  };
70
87
  }
71
- return groupAggregationLookup;
88
+ return {
89
+ groupAggregationLookup,
90
+ aggregatedValues
91
+ };
72
92
  };
73
93
  const getGroupAggregatedValueDataSource = (groupId, apiRef, aggregatedFields, position) => {
74
94
  const groupAggregationLookup = {};
@@ -83,21 +103,37 @@ const getGroupAggregatedValueDataSource = (groupId, apiRef, aggregatedFields, po
83
103
  };
84
104
  const createAggregationLookup = ({
85
105
  apiRef,
86
- aggregationFunctions,
106
+ aggregationRules,
107
+ aggregatedFields,
87
108
  aggregationRowsScope,
88
109
  getAggregationPosition,
89
- isDataSource
110
+ isDataSource,
111
+ applySorting = false
90
112
  }) => {
91
- const aggregationRules = (0, _gridAggregationUtils.getAggregationRules)((0, _xDataGridPro.gridColumnLookupSelector)(apiRef), (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef), aggregationFunctions, isDataSource);
92
- const aggregatedFields = Object.keys(aggregationRules);
93
113
  if (aggregatedFields.length === 0) {
94
114
  return {};
95
115
  }
116
+ const columnsLookup = (0, _xDataGridPro.gridColumnLookupSelector)(apiRef);
117
+ const valueGetters = {};
118
+ for (let i = 0; i < aggregatedFields.length; i += 1) {
119
+ const field = aggregatedFields[i];
120
+ const column = columnsLookup[field];
121
+ const valueGetter = row => apiRef.current.getRowValue(row, column);
122
+ valueGetters[field] = valueGetter;
123
+ }
96
124
  const aggregationLookup = {};
97
125
  const rowTree = (0, _xDataGridPro.gridRowTreeSelector)(apiRef);
126
+ const groupAggregatedValuesLookup = new Map();
127
+ const {
128
+ rowIdToIndexMap
129
+ } = (0, _internals.getVisibleRows)(apiRef);
98
130
  const createGroupAggregationLookup = groupNode => {
99
- for (let i = 0; i < groupNode.children.length; i += 1) {
100
- const childId = groupNode.children[i];
131
+ let children = groupNode.children;
132
+ if (applySorting) {
133
+ children = children.toSorted((a, b) => rowIdToIndexMap.get(a) - rowIdToIndexMap.get(b));
134
+ }
135
+ for (let i = 0; i < children.length; i += 1) {
136
+ const childId = children[i];
101
137
  const childNode = rowTree[childId];
102
138
  if (childNode.type === 'group') {
103
139
  createGroupAggregationLookup(childNode);
@@ -108,7 +144,9 @@ const createAggregationLookup = ({
108
144
  if (isDataSource) {
109
145
  aggregationLookup[groupNode.id] = getGroupAggregatedValueDataSource(groupNode.id, apiRef, aggregatedFields, position);
110
146
  } else if (groupNode.children.length) {
111
- aggregationLookup[groupNode.id] = getGroupAggregatedValue(groupNode.id, apiRef, aggregationRowsScope, aggregatedFields, aggregationRules, position);
147
+ const result = getGroupAggregatedValue(groupNode.id, apiRef, aggregationRowsScope, aggregatedFields, aggregationRules, position, applySorting, valueGetters, apiRef.current, groupAggregatedValuesLookup);
148
+ aggregationLookup[groupNode.id] = result.groupAggregationLookup;
149
+ groupAggregatedValuesLookup.set(groupNode.id, result.aggregatedValues);
112
150
  }
113
151
  }
114
152
  };
@@ -12,7 +12,7 @@ const sumAgg = {
12
12
  let sum = 0;
13
13
  for (let i = 0; i < values.length; i += 1) {
14
14
  const value = values[i];
15
- if ((0, _internals.isNumber)(value)) {
15
+ if (typeof value === 'number' && !Number.isNaN(value)) {
16
16
  sum += value;
17
17
  }
18
18
  }
@@ -31,7 +31,7 @@ const avgAgg = {
31
31
  let valuesCount = 0;
32
32
  for (let i = 0; i < values.length; i += 1) {
33
33
  const value = values[i];
34
- if ((0, _internals.isNumber)(value)) {
34
+ if (typeof value === 'number' && !Number.isNaN(value)) {
35
35
  valuesCount += 1;
36
36
  sum += value;
37
37
  }
@@ -1,4 +1,5 @@
1
1
  import { GridRowId, GridRowModel, GridColDef, GridValueFormatter } from '@mui/x-data-grid-pro';
2
+ import { GridApiPremium } from "../../../models/gridApiPremium.js";
2
3
  export interface GridAggregationState {
3
4
  model: GridAggregationModel;
4
5
  lookup: GridAggregationLookup;
@@ -28,6 +29,10 @@ export interface GridAggregationGetCellValueParams {
28
29
  * The row model of the row that the current cell belongs to.
29
30
  */
30
31
  row: GridRowModel;
32
+ /**
33
+ * The field of the cell that the aggregation function is applied to.
34
+ */
35
+ field: GridColDef['field'];
31
36
  }
32
37
  /**
33
38
  * Grid aggregation function definition interface.
@@ -39,9 +44,10 @@ export interface GridAggregationFunction<V = any, AV = V> {
39
44
  * Function that takes the current cell values and generates the aggregated value.
40
45
  * @template V, AV
41
46
  * @param {GridAggregationParams<V>} params The params of the current aggregated cell.
47
+ * @param {GridApiPremium} api The grid API.
42
48
  * @returns {AV} The aggregated value.
43
49
  */
44
- apply: (params: GridAggregationParams<V>) => AV | null | undefined;
50
+ apply: (params: GridAggregationParams<V>, api: GridApiPremium) => AV | null | undefined;
45
51
  /**
46
52
  * Label of the aggregation function.
47
53
  * Used for adding a label to the footer of the grouping column when this aggregation function is the only one being used.
@@ -72,6 +78,12 @@ export interface GridAggregationFunction<V = any, AV = V> {
72
78
  * @returns {V} The value of the cell that will be passed to the aggregation `apply` function
73
79
  */
74
80
  getCellValue?: (params: GridAggregationGetCellValueParams) => V;
81
+ /**
82
+ * Indicates if the aggregation function depends on rows being in a sorted order.
83
+ * If `true`, the values provided to `apply` will be sorted.
84
+ * @default false
85
+ */
86
+ applySorting?: boolean;
75
87
  }
76
88
  /**
77
89
  * Grid aggregation function data source definition interface.
@@ -1,5 +1,5 @@
1
1
  import { RefObject } from '@mui/x-internals/types';
2
- import { GridColDef, GridRowId } from '@mui/x-data-grid-pro';
2
+ import { GridColDef, GridRowId, GridGroupNode } from '@mui/x-data-grid-pro';
3
3
  import { GridColumnRawLookup, GridHydrateRowsValue } from '@mui/x-data-grid-pro/internals';
4
4
  import { GridAggregationFunction, GridAggregationFunctionDataSource, GridAggregationModel, GridAggregationRule, GridAggregationRules } from "./gridAggregationInterfaces.js";
5
5
  import { GridStatePremium } from "../../../models/gridStatePremium.js";
@@ -59,4 +59,5 @@ export declare const getAggregationFunctionLabel: ({
59
59
  apiRef: RefObject<GridApiPremium>;
60
60
  aggregationRule: GridAggregationRule;
61
61
  }) => string;
62
+ export declare const defaultGetAggregationPosition: (groupNode: GridGroupNode) => "inline" | "footer";
62
63
  export {};
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.mergeStateWithAggregationModel = exports.getAvailableAggregationFunctions = exports.getAggregationRules = exports.getAggregationFunctionLabel = exports.getAggregationFooterRowIdFromGroupId = exports.canColumnHaveAggregationFunction = exports.areAggregationRulesEqual = exports.addFooterRows = exports.GRID_AGGREGATION_ROOT_FOOTER_ROW_ID = void 0;
7
+ exports.mergeStateWithAggregationModel = exports.getAvailableAggregationFunctions = exports.getAggregationRules = exports.getAggregationFunctionLabel = exports.getAggregationFooterRowIdFromGroupId = exports.defaultGetAggregationPosition = exports.canColumnHaveAggregationFunction = exports.areAggregationRulesEqual = exports.addFooterRows = exports.GRID_AGGREGATION_ROOT_FOOTER_ROW_ID = void 0;
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
  var _capitalize = _interopRequireDefault(require("@mui/utils/capitalize"));
10
10
  var _internals = require("@mui/x-data-grid/internals");
@@ -192,4 +192,6 @@ const getAggregationFunctionLabel = ({
192
192
  return aggregationRule.aggregationFunctionName;
193
193
  }
194
194
  };
195
- exports.getAggregationFunctionLabel = getAggregationFunctionLabel;
195
+ exports.getAggregationFunctionLabel = getAggregationFunctionLabel;
196
+ const defaultGetAggregationPosition = groupNode => groupNode.depth === -1 ? 'footer' : 'inline';
197
+ exports.defaultGetAggregationPosition = defaultGetAggregationPosition;
@@ -44,20 +44,95 @@ const useGridAggregation = (apiRef, props) => {
44
44
  apiRef.current.setState((0, _gridAggregationUtils.mergeStateWithAggregationModel)(model));
45
45
  }
46
46
  }, [apiRef]);
47
- const applyAggregation = React.useCallback(() => {
48
- const aggregationLookup = (0, _createAggregationLookup.createAggregationLookup)({
49
- apiRef,
50
- getAggregationPosition: props.getAggregationPosition,
51
- aggregationFunctions: props.aggregationFunctions,
52
- aggregationRowsScope: props.aggregationRowsScope,
53
- isDataSource: !!props.dataSource
54
- });
55
- apiRef.current.setState(state => (0, _extends2.default)({}, state, {
56
- aggregation: (0, _extends2.default)({}, state.aggregation, {
57
- lookup: aggregationLookup
58
- })
59
- }));
47
+ const abortControllerRef = React.useRef(null);
48
+ const applyAggregation = React.useCallback(reason => {
49
+ // Abort previous if any
50
+ if (abortControllerRef.current) {
51
+ abortControllerRef.current.abort();
52
+ }
53
+ const abortController = new AbortController();
54
+ abortControllerRef.current = abortController;
55
+ const aggregationRules = (0, _gridAggregationUtils.getAggregationRules)((0, _xDataGridPro.gridColumnLookupSelector)(apiRef), (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef), props.aggregationFunctions, !!props.dataSource);
56
+ const aggregatedFields = Object.keys(aggregationRules);
57
+ const needsSorting = (0, _createAggregationLookup.shouldApplySorting)(aggregationRules, aggregatedFields);
58
+ if (reason === 'sort' && !needsSorting) {
59
+ // no need to re-apply aggregation on `sortedRowsSet` if sorting is not needed
60
+ return;
61
+ }
62
+ const renderContext = (0, _xDataGridPro.gridRenderContextSelector)(apiRef);
63
+ const visibleColumns = (0, _xDataGridPro.gridVisibleColumnFieldsSelector)(apiRef);
64
+ const chunks = [];
65
+ const visibleAggregatedFields = visibleColumns.slice(renderContext.firstColumnIndex, renderContext.lastColumnIndex + 1).filter(field => aggregatedFields.includes(field));
66
+ if (visibleAggregatedFields.length > 0) {
67
+ chunks.push(visibleAggregatedFields);
68
+ }
69
+ const otherAggregatedFields = aggregatedFields.filter(field => !visibleAggregatedFields.includes(field));
70
+ const chunkSize = 20; // columns per chunk
71
+ for (let i = 0; i < otherAggregatedFields.length; i += chunkSize) {
72
+ chunks.push(otherAggregatedFields.slice(i, i + chunkSize));
73
+ }
74
+ let chunkIndex = 0;
75
+ const aggregationLookup = {};
76
+ let chunkStartTime = performance.now();
77
+ const timeLimit = 1000 / 120;
78
+ const processChunk = () => {
79
+ if (abortController.signal.aborted) {
80
+ return;
81
+ }
82
+ const currentChunk = chunks[chunkIndex];
83
+ if (!currentChunk) {
84
+ const sortModel = (0, _xDataGridPro.gridSortModelSelector)(apiRef).map(s => s.field);
85
+ const hasAggregatedSorting = sortModel.some(field => aggregationRules[field]);
86
+ if (hasAggregatedSorting) {
87
+ apiRef.current.applySorting();
88
+ }
89
+ abortControllerRef.current = null;
90
+ return;
91
+ }
92
+ const applySorting = (0, _createAggregationLookup.shouldApplySorting)(aggregationRules, currentChunk);
93
+
94
+ // createAggregationLookup now RETURNS new partial lookup
95
+ const partialLookup = (0, _createAggregationLookup.createAggregationLookup)({
96
+ apiRef,
97
+ getAggregationPosition: props.getAggregationPosition,
98
+ aggregatedFields: currentChunk,
99
+ aggregationRules,
100
+ aggregationRowsScope: props.aggregationRowsScope,
101
+ isDataSource: !!props.dataSource,
102
+ applySorting
103
+ });
104
+ for (const key of Object.keys(partialLookup)) {
105
+ for (const field of Object.keys(partialLookup[key])) {
106
+ aggregationLookup[key] ?? (aggregationLookup[key] = {});
107
+ aggregationLookup[key][field] = partialLookup[key][field];
108
+ }
109
+ }
110
+ apiRef.current.setState(state => (0, _extends2.default)({}, state, {
111
+ aggregation: (0, _extends2.default)({}, state.aggregation, {
112
+ lookup: (0, _extends2.default)({}, aggregationLookup)
113
+ })
114
+ }));
115
+ chunkIndex += 1;
116
+ if (performance.now() - chunkStartTime < timeLimit) {
117
+ processChunk();
118
+ return;
119
+ }
120
+ setTimeout(() => {
121
+ chunkStartTime = performance.now();
122
+ processChunk();
123
+ }, 0);
124
+ };
125
+ processChunk();
60
126
  }, [apiRef, props.getAggregationPosition, props.aggregationFunctions, props.aggregationRowsScope, props.dataSource]);
127
+ React.useEffect(() => {
128
+ return () => {
129
+ if (abortControllerRef.current) {
130
+ abortControllerRef.current.abort();
131
+ abortControllerRef.current = null;
132
+ }
133
+ };
134
+ }, []);
135
+ const deferredApplyAggregation = (0, _xDataGridPro.useRunOncePerLoop)(applyAggregation);
61
136
  const aggregationApi = {
62
137
  setAggregationModel
63
138
  };
@@ -86,17 +161,18 @@ const useGridAggregation = (apiRef, props) => {
86
161
  // Re-apply the row hydration to add / remove the aggregation footers
87
162
  if (!props.dataSource && !(0, _gridAggregationUtils.areAggregationRulesEqual)(rulesOnLastRowHydration, aggregationRules)) {
88
163
  apiRef.current.requestPipeProcessorsApplication('hydrateRows');
89
- applyAggregation();
164
+ deferredApplyAggregation();
90
165
  }
91
166
 
92
167
  // Re-apply the column hydration to wrap / unwrap the aggregated columns
93
168
  if (!(0, _gridAggregationUtils.areAggregationRulesEqual)(rulesOnLastColumnHydration, aggregationRules)) {
94
169
  apiRef.current.requestPipeProcessorsApplication('hydrateColumns');
95
170
  }
96
- }, [apiRef, applyAggregation, props.aggregationFunctions, props.disableAggregation, props.dataSource]);
171
+ }, [apiRef, deferredApplyAggregation, props.aggregationFunctions, props.disableAggregation, props.dataSource]);
97
172
  (0, _xDataGridPro.useGridEvent)(apiRef, 'aggregationModelChange', checkAggregationRulesDiff);
98
173
  (0, _xDataGridPro.useGridEvent)(apiRef, 'columnsChange', checkAggregationRulesDiff);
99
- (0, _xDataGridPro.useGridEvent)(apiRef, 'filteredRowsSet', applyAggregation);
174
+ (0, _xDataGridPro.useGridEvent)(apiRef, 'filteredRowsSet', deferredApplyAggregation);
175
+ (0, _xDataGridPro.useGridEvent)(apiRef, 'sortedRowsSet', () => deferredApplyAggregation('sort'));
100
176
 
101
177
  /**
102
178
  * EFFECTS
@@ -1,6 +1,8 @@
1
- import type { GridColDef } from '@mui/x-data-grid-pro';
1
+ import type { GridColDef, GridRowModel } from '@mui/x-data-grid-pro';
2
2
  import type { GridPivotingPrivateApiCommunity, GridPivotingStatePartial } from '@mui/x-data-grid/internals';
3
+ import type { RefObject } from '@mui/x-internals/types';
3
4
  import type { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
5
+ import type { GridInitialStatePremium } from "../../../models/gridStatePremium.js";
4
6
  export type GridPivotingPropsOverrides = {
5
7
  rows: DataGridPremiumProcessedProps['rows'];
6
8
  columns: DataGridPremiumProcessedProps['columns'];
@@ -66,4 +68,12 @@ export interface GridPivotingPrivateApi extends GridPivotingPrivateApiCommunity
66
68
  targetFieldPosition?: DropPosition;
67
69
  }) => void;
68
70
  }
69
- export type GridPivotingColDefOverrides = Pick<GridColDef, 'width' | 'flex' | 'headerName' | 'description' | 'align' | 'headerAlign' | 'cellClassName' | 'headerClassName' | 'display' | 'maxWidth' | 'minWidth' | 'resizable' | 'sortingOrder'>;
71
+ export type GridPivotingColDefOverrides = Pick<GridColDef, 'width' | 'flex' | 'headerName' | 'description' | 'align' | 'headerAlign' | 'cellClassName' | 'headerClassName' | 'display' | 'maxWidth' | 'minWidth' | 'resizable' | 'sortingOrder'>;
72
+ export interface GridPivotingInternalCache {
73
+ nonPivotDataRef: RefObject<{
74
+ rows: GridRowModel[];
75
+ columns: Map<string, GridColDef>;
76
+ originalRowsProp: readonly GridRowModel[];
77
+ } | undefined>;
78
+ exportedStateRef: RefObject<GridInitialStatePremium | null>;
79
+ }
@@ -4,4 +4,5 @@ import { GridStateInitializer } from '@mui/x-data-grid-pro/internals';
4
4
  import type { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
5
5
  import { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
6
6
  export declare const pivotingStateInitializer: GridStateInitializer<Pick<DataGridPremiumProcessedProps, 'pivotActive' | 'pivotModel' | 'pivotPanelOpen' | 'initialState' | 'disablePivoting' | 'getPivotDerivedColumns' | 'columns'>>;
7
- export declare const useGridPivoting: (apiRef: RefObject<GridPrivateApiPremium>, props: Pick<DataGridPremiumProcessedProps, "pivotActive" | "onPivotActiveChange" | "pivotModel" | "onPivotModelChange" | "pivotPanelOpen" | "onPivotPanelOpenChange" | "disablePivoting" | "getPivotDerivedColumns" | "pivotingColDef" | "aggregationFunctions">, originalColumnsProp: readonly GridColDef[], originalRowsProp: readonly GridRowModel[]) => void;
7
+ export declare const useGridPivoting: (apiRef: RefObject<GridPrivateApiPremium>, props: Pick<DataGridPremiumProcessedProps, "pivotActive" | "onPivotActiveChange" | "pivotModel" | "onPivotModelChange" | "pivotPanelOpen" | "onPivotPanelOpenChange" | "disablePivoting" | "getPivotDerivedColumns" | "pivotingColDef" | "groupingColDef" | "aggregationFunctions">, originalColumnsProp: readonly GridColDef[], originalRowsProp: readonly GridRowModel[]) => void;
8
+ export declare const useGridPivotingExportState: (apiRef: RefObject<GridPrivateApiPremium>) => void;