@mui/x-data-grid-premium
Version:
The Premium plan edition of the MUI X Data Grid Components.
220 lines (212 loc) • 10.1 kB
JavaScript
"use strict";
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useGridAggregation = exports.aggregationStateInitializer = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _isObjectEmpty = require("@mui/x-internals/isObjectEmpty");
var _xDataGridPro = require("@mui/x-data-grid-pro");
var _internals = require("@mui/x-data-grid-pro/internals");
var _gridAggregationSelectors = require("./gridAggregationSelectors");
var _gridAggregationUtils = require("./gridAggregationUtils");
var _createAggregationLookup = require("./createAggregationLookup");
const aggregationStateInitializer = (state, props, apiRef) => {
apiRef.current.caches.aggregation = {
rulesOnLastColumnHydration: {},
rulesOnLastRowHydration: {}
};
return (0, _extends2.default)({}, state, {
aggregation: {
model: props.aggregationModel ?? props.initialState?.aggregation?.model ?? {}
}
});
};
exports.aggregationStateInitializer = aggregationStateInitializer;
const useGridAggregation = (apiRef, props) => {
apiRef.current.registerControlState({
stateId: 'aggregation',
propModel: props.aggregationModel,
propOnChange: props.onAggregationModelChange,
stateSelector: _gridAggregationSelectors.gridAggregationModelSelector,
changeEvent: 'aggregationModelChange'
});
/**
* API METHODS
*/
const setAggregationModel = React.useCallback(model => {
const currentModel = (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef);
if (currentModel !== model) {
apiRef.current.setState((0, _gridAggregationUtils.mergeStateWithAggregationModel)(model));
}
}, [apiRef]);
const abortControllerRef = React.useRef(null);
const applyAggregation = React.useCallback(() => {
// Abort previous if we're proceeding
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
const abortController = new AbortController();
abortControllerRef.current = abortController;
const aggregationRules = (0, _gridAggregationUtils.getAggregationRules)((0, _xDataGridPro.gridColumnLookupSelector)(apiRef), (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef), props.aggregationFunctions, !!props.dataSource);
const aggregatedFields = Object.keys(aggregationRules);
const currentAggregationLookup = (0, _gridAggregationSelectors.gridAggregationLookupSelector)(apiRef);
const renderContext = (0, _xDataGridPro.gridRenderContextSelector)(apiRef);
const visibleColumns = (0, _xDataGridPro.gridVisibleColumnFieldsSelector)(apiRef);
const chunks = [];
const sortedAggregatedFields = (0, _xDataGridPro.gridSortModelSelector)(apiRef).map(s => s.field).filter(field => aggregatedFields.includes(field));
const visibleAggregatedFields = visibleColumns.slice(renderContext.firstColumnIndex, renderContext.lastColumnIndex + 1).filter(field => aggregatedFields.includes(field));
const visibleAggregatedFieldsWithSort = [...visibleAggregatedFields, ...sortedAggregatedFields.filter(field => !visibleAggregatedFields.includes(field))];
const hasAggregatedSortedField = (0, _xDataGridPro.gridRowMaximumTreeDepthSelector)(apiRef) > 1 && sortedAggregatedFields.length > 0;
if (visibleAggregatedFieldsWithSort.length > 0) {
chunks.push(visibleAggregatedFieldsWithSort);
}
const otherAggregatedFields = aggregatedFields.filter(field => !visibleAggregatedFieldsWithSort.includes(field));
const chunkSize = 20; // columns per chunk
for (let i = 0; i < otherAggregatedFields.length; i += chunkSize) {
chunks.push(otherAggregatedFields.slice(i, i + chunkSize));
}
let chunkIndex = 0;
const aggregationLookup = {};
let chunkStartTime = performance.now();
const timeLimit = 1000 / 120;
const processChunk = () => {
if (abortController.signal.aborted) {
return;
}
const currentChunk = chunks[chunkIndex];
if (!currentChunk) {
apiRef.current.publishEvent('aggregationLookupSet');
abortControllerRef.current = null;
return;
}
const applySorting = (0, _createAggregationLookup.shouldApplySorting)(aggregationRules, currentChunk);
// createAggregationLookup now RETURNS new partial lookup
const partialLookup = (0, _createAggregationLookup.createAggregationLookup)({
apiRef,
getAggregationPosition: props.getAggregationPosition,
aggregatedFields: currentChunk,
aggregationRules,
aggregationRowsScope: props.aggregationRowsScope,
isDataSource: !!props.dataSource,
applySorting
});
for (const key of Object.keys(partialLookup)) {
for (const field of Object.keys(partialLookup[key])) {
aggregationLookup[key] ?? (aggregationLookup[key] = {});
aggregationLookup[key][field] = partialLookup[key][field];
}
}
apiRef.current.setState(state => (0, _extends2.default)({}, state, {
aggregation: (0, _extends2.default)({}, state.aggregation, {
lookup: (0, _extends2.default)({}, aggregationLookup)
})
}));
if (chunkIndex === 0 && hasAggregatedSortedField) {
apiRef.current.applySorting();
}
chunkIndex += 1;
if (performance.now() - chunkStartTime < timeLimit) {
processChunk();
return;
}
setTimeout(() => {
chunkStartTime = performance.now();
processChunk();
}, 0);
};
processChunk();
// processChunk() does nothing if there are no aggregated fields
// make sure that the lookup is empty in this case
if (aggregatedFields.length === 0 && !(0, _isObjectEmpty.isObjectEmpty)(currentAggregationLookup)) {
apiRef.current.setState(state => (0, _extends2.default)({}, state, {
aggregation: (0, _extends2.default)({}, state.aggregation, {
lookup: {}
})
}));
}
}, [apiRef, props.getAggregationPosition, props.aggregationFunctions, props.aggregationRowsScope, props.dataSource]);
React.useEffect(() => {
return () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
abortControllerRef.current = null;
}
};
}, []);
const {
schedule: deferredApplyAggregation
} = (0, _xDataGridPro.useRunOncePerLoop)(applyAggregation);
const aggregationApi = {
setAggregationModel
};
const aggregationPrivateApi = {
applyAggregation
};
(0, _xDataGridPro.useGridApiMethod)(apiRef, aggregationApi, 'public');
(0, _xDataGridPro.useGridApiMethod)(apiRef, aggregationPrivateApi, 'private');
const addGetRowsParams = React.useCallback(params => {
return (0, _extends2.default)({}, params, {
aggregationModel: (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef)
});
}, [apiRef]);
(0, _internals.useGridRegisterPipeProcessor)(apiRef, 'getRowsParams', addGetRowsParams);
/**
* EVENTS
*/
const checkAggregationRulesDiff = React.useCallback(() => {
const pivotingActive = (0, _internals.gridPivotActiveSelector)(apiRef);
const {
rulesOnLastRowHydration,
rulesOnLastColumnHydration
} = apiRef.current.caches.aggregation;
const aggregationRules = props.disableAggregation ? {} : (0, _gridAggregationUtils.getAggregationRules)((0, _xDataGridPro.gridColumnLookupSelector)(apiRef), (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef), props.aggregationFunctions, !!props.dataSource);
// Re-apply the row hydration to add / remove the aggregation footers
if ((!props.dataSource || pivotingActive) && !(0, _gridAggregationUtils.areAggregationRulesEqual)(rulesOnLastRowHydration, aggregationRules)) {
apiRef.current.requestPipeProcessorsApplication('hydrateRows');
deferredApplyAggregation();
}
// Re-apply the column hydration to wrap / unwrap the aggregated columns
if (!(0, _gridAggregationUtils.areAggregationRulesEqual)(rulesOnLastColumnHydration, aggregationRules)) {
apiRef.current.requestPipeProcessorsApplication('hydrateColumns');
}
}, [apiRef, deferredApplyAggregation, props.aggregationFunctions, props.disableAggregation, props.dataSource]);
(0, _xDataGridPro.useGridEvent)(apiRef, 'aggregationModelChange', checkAggregationRulesDiff);
(0, _xDataGridPro.useGridEvent)(apiRef, 'columnsChange', checkAggregationRulesDiff);
(0, _xDataGridPro.useGridEvent)(apiRef, 'filteredRowsSet', deferredApplyAggregation);
const lastSortModel = React.useRef((0, _xDataGridPro.gridSortModelSelector)(apiRef));
(0, _xDataGridPro.useGridEvent)(apiRef, 'sortedRowsSet', () => {
const sortModel = (0, _xDataGridPro.gridSortModelSelector)(apiRef);
if (lastSortModel.current === sortModel) {
return;
}
lastSortModel.current = sortModel;
const aggregationRules = (0, _gridAggregationUtils.getAggregationRules)((0, _xDataGridPro.gridColumnLookupSelector)(apiRef), (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef), props.aggregationFunctions, !!props.dataSource);
const aggregatedFields = Object.keys(aggregationRules);
if (!aggregatedFields.length) {
return;
}
const needsSorting = (0, _createAggregationLookup.shouldApplySorting)(aggregationRules, aggregatedFields);
if (!needsSorting) {
return;
}
deferredApplyAggregation();
});
/**
* EFFECTS
*/
React.useEffect(() => {
if (props.aggregationModel !== undefined) {
apiRef.current.setAggregationModel(props.aggregationModel);
}
}, [apiRef, props.aggregationModel]);
React.useEffect(() => {
if (props.getAggregationPosition !== undefined) {
deferredApplyAggregation();
}
}, [deferredApplyAggregation, props.getAggregationPosition]);
};
exports.useGridAggregation = useGridAggregation;