@mui/x-data-grid-premium 5.13.1 → 5.14.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 +44 -1
- package/DataGridPremium/DataGridPremium.js +47 -0
- package/DataGridPremium/useDataGridPremiumComponent.js +6 -1
- 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 +104 -0
- package/hooks/features/aggregation/gridAggregationInterfaces.js +1 -0
- package/hooks/features/aggregation/gridAggregationSelectors.d.ts +4 -0
- package/hooks/features/aggregation/gridAggregationSelectors.js +5 -0
- package/hooks/features/aggregation/gridAggregationUtils.d.ts +40 -0
- package/hooks/features/aggregation/gridAggregationUtils.js +177 -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 +137 -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 +47 -0
- package/legacy/DataGridPremium/useDataGridPremiumComponent.js +6 -1
- 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 +11 -0
- package/legacy/hooks/features/aggregation/gridAggregationUtils.js +189 -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 +140 -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 +46 -1
- package/models/gridApiPremium.d.ts +2 -2
- package/models/gridStatePremium.d.ts +3 -1
- package/modern/DataGridPremium/DataGridPremium.js +47 -0
- package/modern/DataGridPremium/useDataGridPremiumComponent.js +6 -1
- 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 +5 -0
- package/modern/hooks/features/aggregation/gridAggregationUtils.js +175 -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 +135 -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 +47 -0
- package/node/DataGridPremium/useDataGridPremiumComponent.js +8 -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 +17 -0
- package/node/hooks/features/aggregation/gridAggregationUtils.js +212 -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 +161 -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 +4 -4
- 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,51 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
3
|
+
const _excluded = ["formattedValue", "colDef", "cellMode", "row", "api", "getValue", "id", "value", "rowNode", "field", "focusElementRef", "hasFocus", "tabIndex", "isEditable"];
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { getDataGridUtilityClass } from '@mui/x-data-grid';
|
|
6
|
+
import { styled } from '@mui/material/styles';
|
|
7
|
+
import Box from '@mui/material/Box';
|
|
8
|
+
import { unstable_composeClasses as composeClasses } from '@mui/material';
|
|
9
|
+
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
|
|
10
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
|
+
const GridFooterCellRoot = styled(Box, {
|
|
12
|
+
name: 'MuiDataGrid',
|
|
13
|
+
slot: 'FooterCell',
|
|
14
|
+
overridesResolver: (_, styles) => styles.footerCell
|
|
15
|
+
})(({
|
|
16
|
+
theme
|
|
17
|
+
}) => ({
|
|
18
|
+
fontWeight: theme.typography.fontWeightMedium,
|
|
19
|
+
color: theme.palette.primary.dark
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const useUtilityClasses = ownerState => {
|
|
23
|
+
const {
|
|
24
|
+
classes
|
|
25
|
+
} = ownerState;
|
|
26
|
+
const slots = {
|
|
27
|
+
root: ['footerCell']
|
|
28
|
+
};
|
|
29
|
+
return composeClasses(slots, getDataGridUtilityClass, classes);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const GridFooterCell = props => {
|
|
33
|
+
const {
|
|
34
|
+
formattedValue
|
|
35
|
+
} = props,
|
|
36
|
+
other = _objectWithoutPropertiesLoose(props, _excluded);
|
|
37
|
+
|
|
38
|
+
const rootProps = useGridRootProps();
|
|
39
|
+
const ownerState = {
|
|
40
|
+
classes: rootProps.classes
|
|
41
|
+
};
|
|
42
|
+
const classes = useUtilityClasses(ownerState);
|
|
43
|
+
return /*#__PURE__*/_jsx(GridFooterCellRoot, _extends({
|
|
44
|
+
ownerState: ownerState,
|
|
45
|
+
className: classes.root
|
|
46
|
+
}, other, {
|
|
47
|
+
children: formattedValue
|
|
48
|
+
}));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { GridFooterCell };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
|
|
4
|
+
import { GridFooterCell } from './GridFooterCell';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
|
|
7
|
+
const GridGroupingColumnFooterCell = props => {
|
|
8
|
+
const {
|
|
9
|
+
rowNode
|
|
10
|
+
} = props;
|
|
11
|
+
const rootProps = useGridRootProps();
|
|
12
|
+
let marginLeft;
|
|
13
|
+
|
|
14
|
+
if (rowNode.parent == null) {
|
|
15
|
+
marginLeft = 0;
|
|
16
|
+
} else if (rootProps.rowGroupingColumnMode === 'multiple') {
|
|
17
|
+
marginLeft = 2;
|
|
18
|
+
} else {
|
|
19
|
+
marginLeft = rowNode.depth * 2;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return /*#__PURE__*/_jsx(GridFooterCell, _extends({
|
|
23
|
+
sx: {
|
|
24
|
+
ml: marginLeft
|
|
25
|
+
}
|
|
26
|
+
}, props));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export { GridGroupingColumnFooterCell };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { gridColumnLookupSelector, gridFilteredRowsLookupSelector, gridRowIdsSelector, gridRowTreeSelector } from '@mui/x-data-grid-pro';
|
|
2
|
+
import { getAggregationRules } from './gridAggregationUtils';
|
|
3
|
+
import { gridAggregationModelSelector } from './gridAggregationSelectors';
|
|
4
|
+
|
|
5
|
+
const getAggregationCellValue = ({
|
|
6
|
+
apiRef,
|
|
7
|
+
groupId,
|
|
8
|
+
field,
|
|
9
|
+
aggregationFunction,
|
|
10
|
+
aggregationRowsScope
|
|
11
|
+
}) => {
|
|
12
|
+
const rowTree = gridRowTreeSelector(apiRef);
|
|
13
|
+
const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef);
|
|
14
|
+
let rowIds; // TODO: Add custom root id
|
|
15
|
+
|
|
16
|
+
if (groupId === '') {
|
|
17
|
+
rowIds = gridRowIdsSelector(apiRef).filter(rowId => !rowTree[rowId].isAutoGenerated);
|
|
18
|
+
} else {
|
|
19
|
+
rowIds = apiRef.current.getRowGroupChildren({
|
|
20
|
+
groupId
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const values = [];
|
|
25
|
+
rowIds.forEach(rowId => {
|
|
26
|
+
if (aggregationRowsScope === 'filtered' && filteredRowsLookup[rowId] === false) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
values.push(apiRef.current.getCellValue(rowId, field));
|
|
31
|
+
});
|
|
32
|
+
return aggregationFunction.apply({
|
|
33
|
+
values
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getGroupAggregatedValue = ({
|
|
38
|
+
groupId,
|
|
39
|
+
apiRef,
|
|
40
|
+
aggregationRowsScope,
|
|
41
|
+
aggregatedFields,
|
|
42
|
+
aggregationRules,
|
|
43
|
+
position
|
|
44
|
+
}) => {
|
|
45
|
+
const groupAggregationLookup = {};
|
|
46
|
+
|
|
47
|
+
for (let j = 0; j < aggregatedFields.length; j += 1) {
|
|
48
|
+
const aggregatedField = aggregatedFields[j];
|
|
49
|
+
const columnAggregationRules = aggregationRules[aggregatedField];
|
|
50
|
+
groupAggregationLookup[aggregatedField] = {
|
|
51
|
+
position,
|
|
52
|
+
value: getAggregationCellValue({
|
|
53
|
+
apiRef,
|
|
54
|
+
groupId,
|
|
55
|
+
field: aggregatedField,
|
|
56
|
+
aggregationFunction: columnAggregationRules.aggregationFunction,
|
|
57
|
+
aggregationRowsScope
|
|
58
|
+
})
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return groupAggregationLookup;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const createAggregationLookup = ({
|
|
66
|
+
apiRef,
|
|
67
|
+
aggregationFunctions,
|
|
68
|
+
aggregationRowsScope,
|
|
69
|
+
getAggregationPosition
|
|
70
|
+
}) => {
|
|
71
|
+
const aggregationRules = getAggregationRules({
|
|
72
|
+
columnsLookup: gridColumnLookupSelector(apiRef),
|
|
73
|
+
aggregationModel: gridAggregationModelSelector(apiRef),
|
|
74
|
+
aggregationFunctions
|
|
75
|
+
});
|
|
76
|
+
const aggregatedFields = Object.keys(aggregationRules);
|
|
77
|
+
|
|
78
|
+
if (aggregatedFields.length === 0) {
|
|
79
|
+
return {};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const aggregationLookup = {};
|
|
83
|
+
const rowIds = gridRowIdsSelector(apiRef);
|
|
84
|
+
const rowTree = gridRowTreeSelector(apiRef);
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < rowIds.length; i += 1) {
|
|
87
|
+
const rowId = rowIds[i];
|
|
88
|
+
const node = rowTree[rowId];
|
|
89
|
+
const hasChildren = node.children?.some(childId => (rowTree[childId].position ?? 'body') === 'body');
|
|
90
|
+
|
|
91
|
+
if (hasChildren) {
|
|
92
|
+
const position = getAggregationPosition(node);
|
|
93
|
+
|
|
94
|
+
if (position != null) {
|
|
95
|
+
aggregationLookup[rowId] = getGroupAggregatedValue({
|
|
96
|
+
groupId: rowId,
|
|
97
|
+
apiRef,
|
|
98
|
+
aggregatedFields,
|
|
99
|
+
aggregationRowsScope,
|
|
100
|
+
aggregationRules,
|
|
101
|
+
position
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
} // TODO: Add custom root id
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
const position = getAggregationPosition(null);
|
|
109
|
+
|
|
110
|
+
if (position != null) {
|
|
111
|
+
aggregationLookup[''] = getGroupAggregatedValue({
|
|
112
|
+
groupId: '',
|
|
113
|
+
apiRef,
|
|
114
|
+
aggregatedFields,
|
|
115
|
+
aggregationRowsScope,
|
|
116
|
+
aggregationRules,
|
|
117
|
+
position
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return aggregationLookup;
|
|
122
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { isNumber } from '@mui/x-data-grid-pro/internals';
|
|
2
|
+
const sumAgg = {
|
|
3
|
+
apply: ({
|
|
4
|
+
values
|
|
5
|
+
}) => {
|
|
6
|
+
let sum = 0;
|
|
7
|
+
|
|
8
|
+
for (let i = 0; i < values.length; i += 1) {
|
|
9
|
+
const value = values[i];
|
|
10
|
+
|
|
11
|
+
if (value != null) {
|
|
12
|
+
sum += value;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return sum;
|
|
17
|
+
},
|
|
18
|
+
columnTypes: ['number']
|
|
19
|
+
};
|
|
20
|
+
const avgAgg = {
|
|
21
|
+
apply: params => {
|
|
22
|
+
if (params.values.length === 0) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sum = sumAgg.apply(params);
|
|
27
|
+
return sum / params.values.length;
|
|
28
|
+
},
|
|
29
|
+
columnTypes: ['number']
|
|
30
|
+
};
|
|
31
|
+
const minAgg = {
|
|
32
|
+
apply: ({
|
|
33
|
+
values
|
|
34
|
+
}) => {
|
|
35
|
+
if (values.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let min = +Infinity;
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < values.length; i += 1) {
|
|
42
|
+
const value = values[i];
|
|
43
|
+
|
|
44
|
+
if (value != null && value < min) {
|
|
45
|
+
min = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return min;
|
|
50
|
+
},
|
|
51
|
+
columnTypes: ['number', 'date', 'dateTime']
|
|
52
|
+
};
|
|
53
|
+
const maxAgg = {
|
|
54
|
+
apply: ({
|
|
55
|
+
values
|
|
56
|
+
}) => {
|
|
57
|
+
if (values.length === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let max = -Infinity;
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < values.length; i += 1) {
|
|
64
|
+
const value = values[i];
|
|
65
|
+
|
|
66
|
+
if (value != null && value > max) {
|
|
67
|
+
max = value;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return max;
|
|
72
|
+
},
|
|
73
|
+
columnTypes: ['number', 'date', 'dateTime']
|
|
74
|
+
};
|
|
75
|
+
const sizeAgg = {
|
|
76
|
+
apply: ({
|
|
77
|
+
values
|
|
78
|
+
}) => {
|
|
79
|
+
return values.length;
|
|
80
|
+
},
|
|
81
|
+
valueFormatter: params => {
|
|
82
|
+
if (params.value == null || !isNumber(params.value)) {
|
|
83
|
+
return params.value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return params.value.toLocaleString();
|
|
87
|
+
},
|
|
88
|
+
hasCellUnit: false
|
|
89
|
+
};
|
|
90
|
+
export const PRIVATE_GRID_AGGREGATION_FUNCTIONS = {
|
|
91
|
+
sum: sumAgg,
|
|
92
|
+
avg: avgAgg,
|
|
93
|
+
min: minAgg,
|
|
94
|
+
max: maxAgg,
|
|
95
|
+
size: sizeAgg
|
|
96
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createSelector } from '@mui/x-data-grid-pro/internals';
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3
|
+
export const private_gridAggregationStateSelector = state => state.private_aggregation;
|
|
4
|
+
export const gridAggregationModelSelector = createSelector(private_gridAggregationStateSelector, aggregationState => aggregationState.model);
|
|
5
|
+
export const gridAggregationLookupSelector = createSelector(private_gridAggregationStateSelector, aggregationState => aggregationState.lookup);
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import { capitalize } from '@mui/material';
|
|
3
|
+
import { isDeepEqual } from '@mui/x-data-grid-pro/internals';
|
|
4
|
+
export const PRIVATE_GRID_AGGREGATION_ROOT_FOOTER_ROW_ID = 'auto-generated-group-footer-root'; // eslint-disable-next-line @typescript-eslint/naming-convention
|
|
5
|
+
|
|
6
|
+
export const private_getAggregationFooterRowIdFromGroupId = groupId => {
|
|
7
|
+
if (groupId == null) {
|
|
8
|
+
return PRIVATE_GRID_AGGREGATION_ROOT_FOOTER_ROW_ID;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return `auto-generated-group-footer-${groupId}`;
|
|
12
|
+
};
|
|
13
|
+
export const canColumnHaveAggregationFunction = ({
|
|
14
|
+
column,
|
|
15
|
+
aggregationFunctionName,
|
|
16
|
+
aggregationFunction
|
|
17
|
+
}) => {
|
|
18
|
+
if (!column || !column.private_aggregable) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!aggregationFunction) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (column.private_availableAggregationFunctions != null) {
|
|
27
|
+
return column.private_availableAggregationFunctions.includes(aggregationFunctionName);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!aggregationFunction.columnTypes) {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return aggregationFunction.columnTypes.includes(column.type);
|
|
35
|
+
};
|
|
36
|
+
export const getAvailableAggregationFunctions = ({
|
|
37
|
+
aggregationFunctions,
|
|
38
|
+
column
|
|
39
|
+
}) => Object.keys(aggregationFunctions).filter(aggregationFunctionName => canColumnHaveAggregationFunction({
|
|
40
|
+
column,
|
|
41
|
+
aggregationFunctionName,
|
|
42
|
+
aggregationFunction: aggregationFunctions[aggregationFunctionName]
|
|
43
|
+
}));
|
|
44
|
+
export const mergeStateWithAggregationModel = aggregationModel => state => _extends({}, state, {
|
|
45
|
+
private_aggregation: _extends({}, state.private_aggregation, {
|
|
46
|
+
model: aggregationModel
|
|
47
|
+
})
|
|
48
|
+
});
|
|
49
|
+
export const getAggregationRules = ({
|
|
50
|
+
columnsLookup,
|
|
51
|
+
aggregationModel,
|
|
52
|
+
aggregationFunctions
|
|
53
|
+
}) => {
|
|
54
|
+
const aggregationRules = {};
|
|
55
|
+
Object.entries(aggregationModel).forEach(([field, columnItem]) => {
|
|
56
|
+
if (columnsLookup[field] && canColumnHaveAggregationFunction({
|
|
57
|
+
column: columnsLookup[field],
|
|
58
|
+
aggregationFunctionName: columnItem,
|
|
59
|
+
aggregationFunction: aggregationFunctions[columnItem]
|
|
60
|
+
})) {
|
|
61
|
+
aggregationRules[field] = {
|
|
62
|
+
aggregationFunctionName: columnItem,
|
|
63
|
+
aggregationFunction: aggregationFunctions[columnItem]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return aggregationRules;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Add a footer for each group that has at least one column with an aggregated value.
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
export const addFooterRows = ({
|
|
74
|
+
groupingParams,
|
|
75
|
+
aggregationRules,
|
|
76
|
+
getAggregationPosition
|
|
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 = private_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
|
+
};
|
|
114
|
+
|
|
115
|
+
addGroupFooter(null); // If the tree is flat, we don't need to loop through the rows
|
|
116
|
+
|
|
117
|
+
if (groupingParams.treeDepth > 1) {
|
|
118
|
+
groupingParams.ids.forEach(parentId => {
|
|
119
|
+
const parentNode = tree[parentId];
|
|
120
|
+
|
|
121
|
+
if (parentNode.depth === groupingParams.treeDepth - 1) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
addGroupFooter(parentNode);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return _extends({}, groupingParams, {
|
|
130
|
+
ids,
|
|
131
|
+
idRowsLookup,
|
|
132
|
+
tree
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Compares two sets of aggregation rules to determine if they are equal or not.
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
export const hasAggregationRulesChanged = (previousValue, newValue) => {
|
|
140
|
+
const previousFields = Object.keys(previousValue ?? {});
|
|
141
|
+
const newFields = Object.keys(newValue);
|
|
142
|
+
|
|
143
|
+
if (!isDeepEqual(previousFields, newFields)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return newFields.some(field => {
|
|
148
|
+
const previousRule = previousValue?.[field];
|
|
149
|
+
const newRule = newValue[field];
|
|
150
|
+
|
|
151
|
+
if (previousRule?.aggregationFunction !== newRule?.aggregationFunction) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (previousRule?.aggregationFunctionName !== newRule?.aggregationFunctionName) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return false;
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
export const getAggregationFunctionLabel = ({
|
|
163
|
+
apiRef,
|
|
164
|
+
aggregationRule
|
|
165
|
+
}) => {
|
|
166
|
+
if (aggregationRule.aggregationFunction.label != null) {
|
|
167
|
+
return aggregationRule.aggregationFunction.label;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
return apiRef.current.getLocaleText(`aggregationFunctionLabel${capitalize(aggregationRule.aggregationFunctionName)}`);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return aggregationRule.aggregationFunctionName;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
@@ -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
|
+
private_aggregation: {
|
|
14
|
+
model: props.private_aggregationModel ?? props.initialState?.private_aggregation?.model ?? {}
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
export const useGridAggregation = (apiRef, props) => {
|
|
19
|
+
apiRef.current.unstable_registerControlState({
|
|
20
|
+
stateId: 'aggregation',
|
|
21
|
+
propModel: props.private_aggregationModel,
|
|
22
|
+
propOnChange: props.private_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.private_getAggregationPosition,
|
|
42
|
+
aggregationFunctions: props.private_aggregationFunctions,
|
|
43
|
+
aggregationRowsScope: props.private_aggregationRowsScope
|
|
44
|
+
});
|
|
45
|
+
apiRef.current.setState(state => _extends({}, state, {
|
|
46
|
+
private_aggregation: _extends({}, state.private_aggregation, {
|
|
47
|
+
lookup: aggregationLookup
|
|
48
|
+
})
|
|
49
|
+
}));
|
|
50
|
+
}, [apiRef, props.private_getAggregationPosition, props.private_aggregationFunctions, props.private_aggregationRowsScope]);
|
|
51
|
+
const aggregationApi = {
|
|
52
|
+
private_setAggregationModel: 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.private_disableAggregation ? {} : getAggregationRules({
|
|
65
|
+
columnsLookup: gridColumnLookupSelector(apiRef),
|
|
66
|
+
aggregationModel: gridAggregationModelSelector(apiRef),
|
|
67
|
+
aggregationFunctions: props.private_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.private_aggregationFunctions, props.private_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.private_aggregationModel !== undefined) {
|
|
89
|
+
apiRef.current.private_setAggregationModel(props.private_aggregationModel);
|
|
90
|
+
}
|
|
91
|
+
}, [apiRef, props.private_aggregationModel]);
|
|
92
|
+
};
|