@mui/x-data-grid-premium 5.13.0 → 5.15.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.
- package/CHANGELOG.md +156 -6
- package/DataGridPremium/DataGridPremium.js +56 -0
- package/DataGridPremium/useDataGridPremiumComponent.js +10 -2
- package/DataGridPremium/useDataGridPremiumProps.js +17 -7
- package/components/GridAggregationColumnMenuItem.d.ts +9 -0
- package/components/GridAggregationColumnMenuItem.js +93 -0
- package/components/GridAggregationHeader.d.ts +4 -0
- package/components/GridAggregationHeader.js +94 -0
- package/components/GridExcelExportMenuItem.js +11 -4
- package/components/GridFooterCell.d.ts +9 -0
- package/components/GridFooterCell.js +51 -0
- package/components/GridGroupingColumnFooterCell.d.ts +4 -0
- package/components/GridGroupingColumnFooterCell.js +29 -0
- package/hooks/features/aggregation/createAggregationLookup.d.ts +10 -0
- package/hooks/features/aggregation/createAggregationLookup.js +128 -0
- package/hooks/features/aggregation/gridAggregationFunctions.d.ts +8 -0
- package/hooks/features/aggregation/gridAggregationFunctions.js +96 -0
- package/hooks/features/aggregation/gridAggregationInterfaces.d.ts +103 -0
- package/hooks/features/aggregation/gridAggregationInterfaces.js +1 -0
- package/hooks/features/aggregation/gridAggregationSelectors.d.ts +4 -0
- package/hooks/features/aggregation/gridAggregationSelectors.js +4 -0
- package/hooks/features/aggregation/gridAggregationUtils.d.ts +41 -0
- package/hooks/features/aggregation/gridAggregationUtils.js +188 -0
- package/hooks/features/aggregation/index.d.ts +4 -0
- package/hooks/features/aggregation/index.js +4 -0
- package/hooks/features/aggregation/useGridAggregation.d.ts +6 -0
- package/hooks/features/aggregation/useGridAggregation.js +94 -0
- package/hooks/features/aggregation/useGridAggregationPreProcessors.d.ts +4 -0
- package/hooks/features/aggregation/useGridAggregationPreProcessors.js +138 -0
- package/hooks/features/aggregation/wrapColumnWithAggregation.d.ts +29 -0
- package/hooks/features/aggregation/wrapColumnWithAggregation.js +257 -0
- package/hooks/features/export/serializer/excelSerializer.js +2 -1
- package/hooks/features/index.d.ts +1 -0
- package/hooks/features/index.js +1 -0
- package/hooks/features/rowGrouping/createGroupingColDef.js +13 -2
- package/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
- package/hooks/features/rowGrouping/useGridRowGrouping.d.ts +1 -1
- package/hooks/features/rowGrouping/useGridRowGrouping.js +20 -10
- package/index.js +1 -1
- package/legacy/DataGridPremium/DataGridPremium.js +56 -0
- package/legacy/DataGridPremium/useDataGridPremiumComponent.js +10 -2
- package/legacy/DataGridPremium/useDataGridPremiumProps.js +12 -2
- package/legacy/components/GridAggregationColumnMenuItem.js +95 -0
- package/legacy/components/GridAggregationHeader.js +95 -0
- package/legacy/components/GridExcelExportMenuItem.js +11 -4
- package/legacy/components/GridFooterCell.js +63 -0
- package/legacy/components/GridGroupingColumnFooterCell.js +27 -0
- package/legacy/hooks/features/aggregation/createAggregationLookup.js +127 -0
- package/legacy/hooks/features/aggregation/gridAggregationFunctions.js +94 -0
- package/legacy/hooks/features/aggregation/gridAggregationInterfaces.js +1 -0
- package/legacy/hooks/features/aggregation/gridAggregationSelectors.js +10 -0
- package/legacy/hooks/features/aggregation/gridAggregationUtils.js +200 -0
- package/legacy/hooks/features/aggregation/index.js +4 -0
- package/legacy/hooks/features/aggregation/useGridAggregation.js +95 -0
- package/legacy/hooks/features/aggregation/useGridAggregationPreProcessors.js +141 -0
- package/legacy/hooks/features/aggregation/wrapColumnWithAggregation.js +262 -0
- package/legacy/hooks/features/export/serializer/excelSerializer.js +2 -1
- package/legacy/hooks/features/index.js +1 -0
- package/legacy/hooks/features/rowGrouping/createGroupingColDef.js +13 -2
- package/legacy/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
- package/legacy/hooks/features/rowGrouping/useGridRowGrouping.js +24 -10
- package/legacy/index.js +1 -1
- package/legacy/typeOverloads/index.js +1 -1
- package/legacy/utils/releaseInfo.js +1 -1
- package/models/dataGridPremiumProps.d.ts +40 -1
- package/models/gridApiPremium.d.ts +3 -3
- package/models/gridStatePremium.d.ts +3 -1
- package/modern/DataGridPremium/DataGridPremium.js +56 -0
- package/modern/DataGridPremium/useDataGridPremiumComponent.js +10 -2
- package/modern/DataGridPremium/useDataGridPremiumProps.js +8 -2
- package/modern/components/GridAggregationColumnMenuItem.js +93 -0
- package/modern/components/GridAggregationHeader.js +92 -0
- package/modern/components/GridExcelExportMenuItem.js +11 -4
- package/modern/components/GridFooterCell.js +51 -0
- package/modern/components/GridGroupingColumnFooterCell.js +29 -0
- package/modern/hooks/features/aggregation/createAggregationLookup.js +122 -0
- package/modern/hooks/features/aggregation/gridAggregationFunctions.js +96 -0
- package/modern/hooks/features/aggregation/gridAggregationInterfaces.js +1 -0
- package/modern/hooks/features/aggregation/gridAggregationSelectors.js +4 -0
- package/modern/hooks/features/aggregation/gridAggregationUtils.js +186 -0
- package/modern/hooks/features/aggregation/index.js +4 -0
- package/modern/hooks/features/aggregation/useGridAggregation.js +92 -0
- package/modern/hooks/features/aggregation/useGridAggregationPreProcessors.js +136 -0
- package/modern/hooks/features/aggregation/wrapColumnWithAggregation.js +251 -0
- package/modern/hooks/features/export/serializer/excelSerializer.js +2 -1
- package/modern/hooks/features/index.js +1 -0
- package/modern/hooks/features/rowGrouping/createGroupingColDef.js +13 -2
- package/modern/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
- package/modern/hooks/features/rowGrouping/useGridRowGrouping.js +17 -11
- package/modern/index.js +1 -1
- package/modern/typeOverloads/index.js +1 -1
- package/modern/utils/releaseInfo.js +1 -1
- package/node/DataGridPremium/DataGridPremium.js +56 -0
- package/node/DataGridPremium/useDataGridPremiumComponent.js +11 -1
- package/node/DataGridPremium/useDataGridPremiumProps.js +17 -6
- package/node/components/GridAggregationColumnMenuItem.js +120 -0
- package/node/components/GridAggregationHeader.js +115 -0
- package/node/components/GridExcelExportMenuItem.js +12 -4
- package/node/components/GridFooterCell.js +73 -0
- package/node/components/GridGroupingColumnFooterCell.js +46 -0
- package/node/hooks/features/aggregation/createAggregationLookup.js +139 -0
- package/node/hooks/features/aggregation/gridAggregationFunctions.js +105 -0
- package/node/hooks/features/aggregation/gridAggregationInterfaces.js +5 -0
- package/node/hooks/features/aggregation/gridAggregationSelectors.js +16 -0
- package/node/hooks/features/aggregation/gridAggregationUtils.js +223 -0
- package/node/hooks/features/aggregation/index.js +65 -0
- package/node/hooks/features/aggregation/useGridAggregation.js +118 -0
- package/node/hooks/features/aggregation/useGridAggregationPreProcessors.js +162 -0
- package/node/hooks/features/aggregation/wrapColumnWithAggregation.js +279 -0
- package/node/hooks/features/export/serializer/excelSerializer.js +2 -1
- package/node/hooks/features/index.js +13 -0
- package/node/hooks/features/rowGrouping/createGroupingColDef.js +14 -2
- package/node/hooks/features/rowGrouping/gridRowGroupingUtils.js +5 -1
- package/node/hooks/features/rowGrouping/useGridRowGrouping.js +19 -10
- package/node/index.js +1 -1
- package/node/typeOverloads/index.js +16 -1
- package/node/utils/releaseInfo.js +1 -1
- package/package.json +5 -5
- package/typeOverloads/index.d.ts +1 -1
- package/typeOverloads/index.js +1 -1
- package/typeOverloads/modules.d.ts +32 -2
- package/utils/releaseInfo.js +1 -1
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import { capitalize } from '@mui/material';
|
|
3
|
+
import { addPinnedRow, isDeepEqual } from '@mui/x-data-grid-pro/internals';
|
|
4
|
+
export const GRID_AGGREGATION_ROOT_FOOTER_ROW_ID = 'auto-generated-group-footer-root';
|
|
5
|
+
export const getAggregationFooterRowIdFromGroupId = groupId => {
|
|
6
|
+
if (groupId == null) {
|
|
7
|
+
return GRID_AGGREGATION_ROOT_FOOTER_ROW_ID;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return `auto-generated-group-footer-${groupId}`;
|
|
11
|
+
};
|
|
12
|
+
export const canColumnHaveAggregationFunction = ({
|
|
13
|
+
column,
|
|
14
|
+
aggregationFunctionName,
|
|
15
|
+
aggregationFunction
|
|
16
|
+
}) => {
|
|
17
|
+
if (!column || !column.aggregable) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!aggregationFunction) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (column.availableAggregationFunctions != null) {
|
|
26
|
+
return column.availableAggregationFunctions.includes(aggregationFunctionName);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!aggregationFunction.columnTypes) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return aggregationFunction.columnTypes.includes(column.type);
|
|
34
|
+
};
|
|
35
|
+
export const getAvailableAggregationFunctions = ({
|
|
36
|
+
aggregationFunctions,
|
|
37
|
+
column
|
|
38
|
+
}) => Object.keys(aggregationFunctions).filter(aggregationFunctionName => canColumnHaveAggregationFunction({
|
|
39
|
+
column,
|
|
40
|
+
aggregationFunctionName,
|
|
41
|
+
aggregationFunction: aggregationFunctions[aggregationFunctionName]
|
|
42
|
+
}));
|
|
43
|
+
export const mergeStateWithAggregationModel = aggregationModel => state => _extends({}, state, {
|
|
44
|
+
aggregation: _extends({}, state.aggregation, {
|
|
45
|
+
model: aggregationModel
|
|
46
|
+
})
|
|
47
|
+
});
|
|
48
|
+
export const getAggregationRules = ({
|
|
49
|
+
columnsLookup,
|
|
50
|
+
aggregationModel,
|
|
51
|
+
aggregationFunctions
|
|
52
|
+
}) => {
|
|
53
|
+
const aggregationRules = {};
|
|
54
|
+
Object.entries(aggregationModel).forEach(([field, columnItem]) => {
|
|
55
|
+
if (columnsLookup[field] && canColumnHaveAggregationFunction({
|
|
56
|
+
column: columnsLookup[field],
|
|
57
|
+
aggregationFunctionName: columnItem,
|
|
58
|
+
aggregationFunction: aggregationFunctions[columnItem]
|
|
59
|
+
})) {
|
|
60
|
+
aggregationRules[field] = {
|
|
61
|
+
aggregationFunctionName: columnItem,
|
|
62
|
+
aggregationFunction: aggregationFunctions[columnItem]
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return aggregationRules;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Add a footer for each group that has at least one column with an aggregated value.
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
export const addFooterRows = ({
|
|
73
|
+
groupingParams,
|
|
74
|
+
aggregationRules,
|
|
75
|
+
getAggregationPosition,
|
|
76
|
+
apiRef
|
|
77
|
+
}) => {
|
|
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
|
+
const groupId = groupNode?.id ?? null;
|
|
90
|
+
|
|
91
|
+
if (getAggregationPosition(groupNode) !== 'footer') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const footerId = getAggregationFooterRowIdFromGroupId(groupId);
|
|
96
|
+
ids.push(footerId);
|
|
97
|
+
idRowsLookup[footerId] = {};
|
|
98
|
+
tree[footerId] = {
|
|
99
|
+
id: footerId,
|
|
100
|
+
isAutoGenerated: true,
|
|
101
|
+
parent: groupId,
|
|
102
|
+
depth: groupNode ? groupNode.depth + 1 : 0,
|
|
103
|
+
groupingKey: null,
|
|
104
|
+
groupingField: null,
|
|
105
|
+
position: 'footer'
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
if (groupId != null) {
|
|
109
|
+
tree[groupId] = _extends({}, tree[groupId], {
|
|
110
|
+
footerId
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}; // If the tree is flat, we don't need to loop through the rows
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
if (groupingParams.treeDepth > 1) {
|
|
117
|
+
groupingParams.ids.forEach(parentId => {
|
|
118
|
+
const parentNode = tree[parentId];
|
|
119
|
+
|
|
120
|
+
if (parentNode.depth === groupingParams.treeDepth - 1) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
addGroupFooter(parentNode);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
let newGroupingParams = _extends({}, groupingParams, {
|
|
129
|
+
tree,
|
|
130
|
+
idRowsLookup,
|
|
131
|
+
ids
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (getAggregationPosition(null) === 'footer') {
|
|
135
|
+
newGroupingParams = addPinnedRow({
|
|
136
|
+
groupingParams: newGroupingParams,
|
|
137
|
+
rowModel: {},
|
|
138
|
+
rowId: getAggregationFooterRowIdFromGroupId(null),
|
|
139
|
+
position: 'bottom',
|
|
140
|
+
apiRef
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return _extends({}, groupingParams, newGroupingParams);
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Compares two sets of aggregation rules to determine if they are equal or not.
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
export const hasAggregationRulesChanged = (previousValue, newValue) => {
|
|
151
|
+
const previousFields = Object.keys(previousValue ?? {});
|
|
152
|
+
const newFields = Object.keys(newValue);
|
|
153
|
+
|
|
154
|
+
if (!isDeepEqual(previousFields, newFields)) {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return newFields.some(field => {
|
|
159
|
+
const previousRule = previousValue?.[field];
|
|
160
|
+
const newRule = newValue[field];
|
|
161
|
+
|
|
162
|
+
if (previousRule?.aggregationFunction !== newRule?.aggregationFunction) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (previousRule?.aggregationFunctionName !== newRule?.aggregationFunctionName) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return false;
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
export const getAggregationFunctionLabel = ({
|
|
174
|
+
apiRef,
|
|
175
|
+
aggregationRule
|
|
176
|
+
}) => {
|
|
177
|
+
if (aggregationRule.aggregationFunction.label != null) {
|
|
178
|
+
return aggregationRule.aggregationFunction.label;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
return apiRef.current.getLocaleText(`aggregationFunctionLabel${capitalize(aggregationRule.aggregationFunctionName)}`);
|
|
183
|
+
} catch (e) {
|
|
184
|
+
return aggregationRule.aggregationFunctionName;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { gridColumnLookupSelector, useGridApiEventHandler, useGridApiMethod } from '@mui/x-data-grid-pro';
|
|
4
|
+
import { gridAggregationModelSelector } from './gridAggregationSelectors';
|
|
5
|
+
import { getAggregationRules, mergeStateWithAggregationModel, hasAggregationRulesChanged } from './gridAggregationUtils';
|
|
6
|
+
import { createAggregationLookup } from './createAggregationLookup';
|
|
7
|
+
export const aggregationStateInitializer = (state, props, apiRef) => {
|
|
8
|
+
apiRef.current.unstable_caches.aggregation = {
|
|
9
|
+
rulesOnLastColumnHydration: {},
|
|
10
|
+
rulesOnLastRowHydration: {}
|
|
11
|
+
};
|
|
12
|
+
return _extends({}, state, {
|
|
13
|
+
aggregation: {
|
|
14
|
+
model: props.aggregationModel ?? props.initialState?.aggregation?.model ?? {}
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
export const useGridAggregation = (apiRef, props) => {
|
|
19
|
+
apiRef.current.unstable_registerControlState({
|
|
20
|
+
stateId: 'aggregation',
|
|
21
|
+
propModel: props.aggregationModel,
|
|
22
|
+
propOnChange: props.onAggregationModelChange,
|
|
23
|
+
stateSelector: gridAggregationModelSelector,
|
|
24
|
+
changeEvent: 'aggregationModelChange'
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* API METHODS
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const setAggregationModel = React.useCallback(model => {
|
|
31
|
+
const currentModel = gridAggregationModelSelector(apiRef);
|
|
32
|
+
|
|
33
|
+
if (currentModel !== model) {
|
|
34
|
+
apiRef.current.setState(mergeStateWithAggregationModel(model));
|
|
35
|
+
apiRef.current.forceUpdate();
|
|
36
|
+
}
|
|
37
|
+
}, [apiRef]);
|
|
38
|
+
const applyAggregation = React.useCallback(() => {
|
|
39
|
+
const aggregationLookup = createAggregationLookup({
|
|
40
|
+
apiRef,
|
|
41
|
+
getAggregationPosition: props.getAggregationPosition,
|
|
42
|
+
aggregationFunctions: props.aggregationFunctions,
|
|
43
|
+
aggregationRowsScope: props.aggregationRowsScope
|
|
44
|
+
});
|
|
45
|
+
apiRef.current.setState(state => _extends({}, state, {
|
|
46
|
+
aggregation: _extends({}, state.aggregation, {
|
|
47
|
+
lookup: aggregationLookup
|
|
48
|
+
})
|
|
49
|
+
}));
|
|
50
|
+
}, [apiRef, props.getAggregationPosition, props.aggregationFunctions, props.aggregationRowsScope]);
|
|
51
|
+
const aggregationApi = {
|
|
52
|
+
setAggregationModel
|
|
53
|
+
};
|
|
54
|
+
useGridApiMethod(apiRef, aggregationApi, 'GridAggregationApi');
|
|
55
|
+
/**
|
|
56
|
+
* EVENTS
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
const checkAggregationRulesDiff = React.useCallback(() => {
|
|
60
|
+
const {
|
|
61
|
+
rulesOnLastRowHydration,
|
|
62
|
+
rulesOnLastColumnHydration
|
|
63
|
+
} = apiRef.current.unstable_caches.aggregation;
|
|
64
|
+
const aggregationRules = props.disableAggregation ? {} : getAggregationRules({
|
|
65
|
+
columnsLookup: gridColumnLookupSelector(apiRef),
|
|
66
|
+
aggregationModel: gridAggregationModelSelector(apiRef),
|
|
67
|
+
aggregationFunctions: props.aggregationFunctions
|
|
68
|
+
}); // Re-apply the row hydration to add / remove the aggregation footers
|
|
69
|
+
|
|
70
|
+
if (hasAggregationRulesChanged(rulesOnLastRowHydration, aggregationRules)) {
|
|
71
|
+
apiRef.current.unstable_requestPipeProcessorsApplication('hydrateRows');
|
|
72
|
+
applyAggregation();
|
|
73
|
+
} // Re-apply the column hydration to wrap / unwrap the aggregated columns
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if (hasAggregationRulesChanged(rulesOnLastColumnHydration, aggregationRules)) {
|
|
77
|
+
apiRef.current.unstable_requestPipeProcessorsApplication('hydrateColumns');
|
|
78
|
+
}
|
|
79
|
+
}, [apiRef, applyAggregation, props.aggregationFunctions, props.disableAggregation]);
|
|
80
|
+
useGridApiEventHandler(apiRef, 'aggregationModelChange', checkAggregationRulesDiff);
|
|
81
|
+
useGridApiEventHandler(apiRef, 'columnsChange', checkAggregationRulesDiff);
|
|
82
|
+
useGridApiEventHandler(apiRef, 'filteredRowsSet', applyAggregation);
|
|
83
|
+
/**
|
|
84
|
+
* EFFECTS
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
React.useEffect(() => {
|
|
88
|
+
if (props.aggregationModel !== undefined) {
|
|
89
|
+
apiRef.current.setAggregationModel(props.aggregationModel);
|
|
90
|
+
}
|
|
91
|
+
}, [apiRef, props.aggregationModel]);
|
|
92
|
+
};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import MuiDivider from '@mui/material/Divider';
|
|
4
|
+
import { gridColumnLookupSelector } from '@mui/x-data-grid-pro';
|
|
5
|
+
import { useGridRegisterPipeProcessor } from '@mui/x-data-grid-pro/internals';
|
|
6
|
+
import { getAvailableAggregationFunctions, addFooterRows, getAggregationRules, mergeStateWithAggregationModel } from './gridAggregationUtils';
|
|
7
|
+
import { wrapColumnWithAggregationValue, unwrapColumnFromAggregation } from './wrapColumnWithAggregation';
|
|
8
|
+
import { GridAggregationColumnMenuItem } from '../../../components/GridAggregationColumnMenuItem';
|
|
9
|
+
import { gridAggregationModelSelector } from './gridAggregationSelectors';
|
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
+
|
|
12
|
+
const Divider = () => /*#__PURE__*/_jsx(MuiDivider, {
|
|
13
|
+
onClick: event => event.stopPropagation()
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const useGridAggregationPreProcessors = (apiRef, props) => {
|
|
17
|
+
const updateAggregatedColumns = React.useCallback(columnsState => {
|
|
18
|
+
const {
|
|
19
|
+
rulesOnLastColumnHydration
|
|
20
|
+
} = apiRef.current.unstable_caches.aggregation;
|
|
21
|
+
const aggregationRules = props.disableAggregation ? {} : getAggregationRules({
|
|
22
|
+
columnsLookup: columnsState.lookup,
|
|
23
|
+
aggregationModel: gridAggregationModelSelector(apiRef),
|
|
24
|
+
aggregationFunctions: props.aggregationFunctions
|
|
25
|
+
});
|
|
26
|
+
columnsState.all.forEach(field => {
|
|
27
|
+
const shouldHaveAggregationValue = !!aggregationRules[field];
|
|
28
|
+
const haveAggregationColumnValue = !!rulesOnLastColumnHydration[field];
|
|
29
|
+
let column = columnsState.lookup[field];
|
|
30
|
+
|
|
31
|
+
if (haveAggregationColumnValue) {
|
|
32
|
+
column = unwrapColumnFromAggregation({
|
|
33
|
+
column
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (shouldHaveAggregationValue) {
|
|
38
|
+
column = wrapColumnWithAggregationValue({
|
|
39
|
+
column,
|
|
40
|
+
aggregationRule: aggregationRules[field],
|
|
41
|
+
apiRef
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
columnsState.lookup[field] = column;
|
|
46
|
+
});
|
|
47
|
+
apiRef.current.unstable_caches.aggregation.rulesOnLastColumnHydration = aggregationRules;
|
|
48
|
+
return columnsState;
|
|
49
|
+
}, [apiRef, props.aggregationFunctions, props.disableAggregation]);
|
|
50
|
+
const addGroupFooterRows = React.useCallback(groupingParams => {
|
|
51
|
+
let newGroupingParams;
|
|
52
|
+
let rulesOnLastRowHydration;
|
|
53
|
+
|
|
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
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
apiRef.current.unstable_caches.aggregation.rulesOnLastRowHydration = rulesOnLastRowHydration;
|
|
79
|
+
return newGroupingParams;
|
|
80
|
+
}, [apiRef, props.disableAggregation, props.getAggregationPosition, props.aggregationFunctions]);
|
|
81
|
+
const addColumnMenuButtons = React.useCallback((initialValue, column) => {
|
|
82
|
+
if (props.disableAggregation) {
|
|
83
|
+
return initialValue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const availableAggregationFunctions = getAvailableAggregationFunctions({
|
|
87
|
+
aggregationFunctions: props.aggregationFunctions,
|
|
88
|
+
column
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (availableAggregationFunctions.length === 0) {
|
|
92
|
+
return initialValue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [...initialValue, /*#__PURE__*/_jsx(Divider, {}), /*#__PURE__*/_jsx(GridAggregationColumnMenuItem, {
|
|
96
|
+
column: column,
|
|
97
|
+
label: apiRef.current.getLocaleText('aggregationMenuItemHeader'),
|
|
98
|
+
availableAggregationFunctions: availableAggregationFunctions
|
|
99
|
+
})];
|
|
100
|
+
}, [apiRef, props.aggregationFunctions, props.disableAggregation]);
|
|
101
|
+
const stateExportPreProcessing = React.useCallback(prevState => {
|
|
102
|
+
if (props.disableAggregation) {
|
|
103
|
+
return prevState;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const aggregationModelToExport = gridAggregationModelSelector(apiRef);
|
|
107
|
+
|
|
108
|
+
if (Object.values(aggregationModelToExport).length === 0) {
|
|
109
|
+
return prevState;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return _extends({}, prevState, {
|
|
113
|
+
aggregation: {
|
|
114
|
+
model: aggregationModelToExport
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}, [apiRef, props.disableAggregation]);
|
|
118
|
+
const stateRestorePreProcessing = React.useCallback((params, context) => {
|
|
119
|
+
if (props.disableAggregation) {
|
|
120
|
+
return params;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const aggregationModel = context.stateToRestore.aggregation?.model;
|
|
124
|
+
|
|
125
|
+
if (aggregationModel != null) {
|
|
126
|
+
apiRef.current.setState(mergeStateWithAggregationModel(aggregationModel));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return params;
|
|
130
|
+
}, [apiRef, props.disableAggregation]);
|
|
131
|
+
useGridRegisterPipeProcessor(apiRef, 'hydrateColumns', updateAggregatedColumns);
|
|
132
|
+
useGridRegisterPipeProcessor(apiRef, 'hydrateRows', addGroupFooterRows);
|
|
133
|
+
useGridRegisterPipeProcessor(apiRef, 'columnMenu', addColumnMenuButtons);
|
|
134
|
+
useGridRegisterPipeProcessor(apiRef, 'exportState', stateExportPreProcessing);
|
|
135
|
+
useGridRegisterPipeProcessor(apiRef, 'restoreState', stateRestorePreProcessing);
|
|
136
|
+
};
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { gridAggregationLookupSelector } from './gridAggregationSelectors';
|
|
4
|
+
import { GridFooterCell } from '../../../components/GridFooterCell';
|
|
5
|
+
import { GridAggregationHeader } from '../../../components/GridAggregationHeader';
|
|
6
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
const AGGREGATION_WRAPPABLE_PROPERTIES = ['valueGetter', 'valueFormatter', 'renderCell', 'renderHeader', 'filterOperators'];
|
|
8
|
+
|
|
9
|
+
const getAggregationValueWrappedValueGetter = ({
|
|
10
|
+
value: valueGetter,
|
|
11
|
+
getCellAggregationResult
|
|
12
|
+
}) => {
|
|
13
|
+
const wrappedValueGetter = params => {
|
|
14
|
+
const cellAggregationResult = getCellAggregationResult(params.id, params.field);
|
|
15
|
+
|
|
16
|
+
if (cellAggregationResult != null) {
|
|
17
|
+
return cellAggregationResult?.value ?? null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (valueGetter) {
|
|
21
|
+
return valueGetter(params);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return params.row[params.field];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return wrappedValueGetter;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const getAggregationValueWrappedValueFormatter = ({
|
|
31
|
+
value: valueFormatter,
|
|
32
|
+
aggregationRule,
|
|
33
|
+
getCellAggregationResult
|
|
34
|
+
}) => {
|
|
35
|
+
// If neither the inline aggregation function nor the footer aggregation function have a custom value formatter,
|
|
36
|
+
// Then we don't wrap the column value formatter
|
|
37
|
+
if (!aggregationRule.aggregationFunction.valueFormatter) {
|
|
38
|
+
return valueFormatter;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const wrappedValueFormatter = params => {
|
|
42
|
+
if (params.id != null) {
|
|
43
|
+
const cellAggregationResult = getCellAggregationResult(params.id, params.field);
|
|
44
|
+
|
|
45
|
+
if (cellAggregationResult != null) {
|
|
46
|
+
return aggregationRule.aggregationFunction.valueFormatter(params);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (valueFormatter) {
|
|
51
|
+
return valueFormatter(params);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return params.value;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return wrappedValueFormatter;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const getAggregationValueWrappedRenderCell = ({
|
|
61
|
+
value: renderCell,
|
|
62
|
+
aggregationRule,
|
|
63
|
+
getCellAggregationResult
|
|
64
|
+
}) => {
|
|
65
|
+
const wrappedRenderCell = params => {
|
|
66
|
+
const cellAggregationResult = getCellAggregationResult(params.id, params.field);
|
|
67
|
+
|
|
68
|
+
if (cellAggregationResult != null) {
|
|
69
|
+
if (!renderCell) {
|
|
70
|
+
if (cellAggregationResult.position === 'footer') {
|
|
71
|
+
return /*#__PURE__*/_jsx(GridFooterCell, _extends({}, params));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return params.formattedValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const aggregationMeta = {
|
|
78
|
+
hasCellUnit: aggregationRule.aggregationFunction.hasCellUnit ?? true,
|
|
79
|
+
aggregationFunctionName: aggregationRule.aggregationFunctionName
|
|
80
|
+
};
|
|
81
|
+
return renderCell(_extends({}, params, {
|
|
82
|
+
aggregation: aggregationMeta
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!renderCell) {
|
|
87
|
+
return params.formattedValue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return renderCell(params);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
return wrappedRenderCell;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Skips the filtering for aggregated rows
|
|
97
|
+
*/
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
const getWrappedFilterOperators = ({
|
|
101
|
+
value: filterOperators,
|
|
102
|
+
getCellAggregationResult
|
|
103
|
+
}) => filterOperators.map(operator => {
|
|
104
|
+
return _extends({}, operator, {
|
|
105
|
+
getApplyFilterFn: (filterItem, column) => {
|
|
106
|
+
const originalFn = operator.getApplyFilterFn(filterItem, column);
|
|
107
|
+
|
|
108
|
+
if (!originalFn) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return params => {
|
|
113
|
+
if (getCellAggregationResult(params.id, params.field) != null) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return originalFn(params);
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* Add the aggregation method around the header name
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
const getWrappedRenderHeader = ({
|
|
128
|
+
value: renderHeader,
|
|
129
|
+
aggregationRule
|
|
130
|
+
}) => {
|
|
131
|
+
const wrappedRenderCell = params => {
|
|
132
|
+
const aggregationMeta = {
|
|
133
|
+
aggregationRule
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (!renderHeader) {
|
|
137
|
+
return /*#__PURE__*/_jsx(GridAggregationHeader, _extends({}, params, {
|
|
138
|
+
aggregation: aggregationMeta
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return renderHeader(_extends({}, params, {
|
|
143
|
+
aggregation: aggregationMeta
|
|
144
|
+
}));
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return wrappedRenderCell;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Add a wrapper around each wrappable property of the column to customize the behavior of the aggregation cells.
|
|
151
|
+
*/
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
export const wrapColumnWithAggregationValue = ({
|
|
155
|
+
column,
|
|
156
|
+
apiRef,
|
|
157
|
+
aggregationRule
|
|
158
|
+
}) => {
|
|
159
|
+
const getCellAggregationResult = (id, field) => {
|
|
160
|
+
let cellAggregationPosition = null;
|
|
161
|
+
|
|
162
|
+
if (id.toString().startsWith('auto-generated-row-')) {
|
|
163
|
+
cellAggregationPosition = 'inline';
|
|
164
|
+
} else if (id.toString().startsWith('auto-generated-group-footer-')) {
|
|
165
|
+
cellAggregationPosition = 'footer';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (cellAggregationPosition == null) {
|
|
169
|
+
return null;
|
|
170
|
+
} // TODO: Add custom root id
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
const groupId = cellAggregationPosition === 'inline' ? id : apiRef.current.getRowNode(id).parent ?? '';
|
|
174
|
+
const aggregationResult = gridAggregationLookupSelector(apiRef)[groupId]?.[field];
|
|
175
|
+
|
|
176
|
+
if (!aggregationResult || aggregationResult.position !== cellAggregationPosition) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return aggregationResult;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const aggregationWrappedProperties = {};
|
|
184
|
+
|
|
185
|
+
const wrappedColumn = _extends({}, column, {
|
|
186
|
+
aggregationWrappedProperties
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const wrapColumnProperty = (property, wrapper) => {
|
|
190
|
+
const originalValue = column[property];
|
|
191
|
+
const wrappedProperty = wrapper({
|
|
192
|
+
apiRef,
|
|
193
|
+
value: originalValue,
|
|
194
|
+
colDef: column,
|
|
195
|
+
aggregationRule,
|
|
196
|
+
getCellAggregationResult
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (wrappedProperty !== originalValue) {
|
|
200
|
+
aggregationWrappedProperties[property] = {
|
|
201
|
+
original: originalValue,
|
|
202
|
+
wrapped: wrappedProperty
|
|
203
|
+
};
|
|
204
|
+
wrappedColumn[property] = wrappedProperty;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
wrapColumnProperty('valueGetter', getAggregationValueWrappedValueGetter);
|
|
209
|
+
wrapColumnProperty('valueFormatter', getAggregationValueWrappedValueFormatter);
|
|
210
|
+
wrapColumnProperty('renderCell', getAggregationValueWrappedRenderCell);
|
|
211
|
+
wrapColumnProperty('renderHeader', getWrappedRenderHeader);
|
|
212
|
+
wrapColumnProperty('filterOperators', getWrappedFilterOperators);
|
|
213
|
+
|
|
214
|
+
if (Object.keys(aggregationWrappedProperties).length === 0) {
|
|
215
|
+
return column;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return wrappedColumn;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Remove the aggregation wrappers around the wrappable properties of the column.
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
export const unwrapColumnFromAggregation = ({
|
|
225
|
+
column
|
|
226
|
+
}) => {
|
|
227
|
+
if (!column.aggregationWrappedProperties) {
|
|
228
|
+
return column;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const originalProperties = Object.entries(column.aggregationWrappedProperties);
|
|
232
|
+
|
|
233
|
+
if (originalProperties.length === 0) {
|
|
234
|
+
return column;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const unwrappedColumn = _extends({}, column);
|
|
238
|
+
|
|
239
|
+
originalProperties.forEach(([propertyName, {
|
|
240
|
+
original,
|
|
241
|
+
wrapped
|
|
242
|
+
}]) => {
|
|
243
|
+
// The value changed since we wrapped it
|
|
244
|
+
if (wrapped !== column[propertyName]) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
unwrappedColumn[propertyName] = original;
|
|
249
|
+
});
|
|
250
|
+
return unwrappedColumn;
|
|
251
|
+
};
|
|
@@ -46,7 +46,8 @@ const serializeRow = (id, columns, api, defaultValueOptionsFormulae) => {
|
|
|
46
46
|
api.unstable_calculateColSpan({
|
|
47
47
|
rowId: id,
|
|
48
48
|
minFirstColumn: 0,
|
|
49
|
-
maxLastColumn: columns.length
|
|
49
|
+
maxLastColumn: columns.length,
|
|
50
|
+
columns
|
|
50
51
|
});
|
|
51
52
|
columns.forEach((column, colIndex) => {
|
|
52
53
|
const colSpanInfo = api.unstable_getCellColSpanInfo(id, colIndex);
|