UNPKG

@mui/x-data-grid-premium

Version:

The Premium plan edition of the MUI X Data Grid Components.

599 lines (584 loc) 31.3 kB
"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.useGridChartsIntegration = exports.chartsIntegrationStateInitializer = exports.EMPTY_CHART_INTEGRATION_CONTEXT_STATE = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _debounce = _interopRequireDefault(require("@mui/utils/debounce")); var _xDataGridPro = require("@mui/x-data-grid-pro"); var _internals = require("@mui/x-data-grid-pro/internals"); var _gridRowGroupingUtils = require("../rowGrouping/gridRowGroupingUtils"); var _gridChartsIntegrationSelectors = require("./gridChartsIntegrationSelectors"); var _useGridChartIntegration = require("../../utils/useGridChartIntegration"); var _utils = require("./utils"); var _gridRowGroupingSelector = require("../rowGrouping/gridRowGroupingSelector"); var _sidebar = require("../sidebar"); var _gridAggregationUtils = require("../aggregation/gridAggregationUtils"); var _gridAggregationSelectors = require("../aggregation/gridAggregationSelectors"); var _gridPivotingSelectors = require("../pivoting/gridPivotingSelectors"); var _jsxRuntime = require("react/jsx-runtime"); const EMPTY_CHART_INTEGRATION_CONTEXT = { chartStateLookup: {}, setChartState: () => {} }; const EMPTY_CHART_INTEGRATION_CONTEXT_STATE = exports.EMPTY_CHART_INTEGRATION_CONTEXT_STATE = { synced: true, dimensions: [], values: [], type: '', configuration: {} }; const chartsIntegrationStateInitializer = (state, props) => { if (!props.chartsIntegration || !props.experimentalFeatures?.charts) { return (0, _extends2.default)({}, state, { chartsIntegration: { activeChartId: '', charts: {} } }); } const rowGroupingModel = (state.rowGrouping?.model ?? []).filter(item => item !== undefined); const pivotModel = state.pivoting?.active ? state.pivoting?.model : undefined; const columnsLookup = state.columns?.lookup ?? {}; const charts = Object.fromEntries(Object.entries(props.initialState?.chartsIntegration?.charts || {}).map(([chartId, chart]) => [chartId, { dimensions: (chart.dimensions || []).map(dimension => typeof dimension === 'string' ? { field: dimension, hidden: false } : dimension).filter(dimension => columnsLookup[dimension.field]?.chartable === true && !(0, _utils.isBlockedForSection)(columnsLookup[dimension.field], 'dimensions', rowGroupingModel, pivotModel)), values: (chart.values || []).map(value => typeof value === 'string' ? { field: value, hidden: false } : value).filter(value => columnsLookup[value.field]?.chartable === true && !(0, _utils.isBlockedForSection)(columnsLookup[value.field], 'values', rowGroupingModel, pivotModel)) }])); return (0, _extends2.default)({}, state, { chartsIntegration: { activeChartId: props.activeChartId ?? props.initialState?.chartsIntegration?.activeChartId ?? '', charts } }); }; exports.chartsIntegrationStateInitializer = chartsIntegrationStateInitializer; const useGridChartsIntegration = (apiRef, props) => { const visibleDimensions = React.useRef({}); const visibleValues = React.useRef({}); const schema = React.useMemo(() => props.slotProps?.chartsPanel?.schema || {}, [props.slotProps?.chartsPanel?.schema]); const context = (0, _useGridChartIntegration.useGridChartsIntegrationContext)(true); const isChartsIntegrationAvailable = !!props.chartsIntegration && !!props.experimentalFeatures?.charts && !!context; const activeChartId = (0, _gridChartsIntegrationSelectors.gridChartsIntegrationActiveChartIdSelector)(apiRef); const aggregationModel = (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef); const pivotActive = (0, _internals.gridPivotActiveSelector)(apiRef); const pivotModel = (0, _gridPivotingSelectors.gridPivotModelSelector)(apiRef); const { chartStateLookup, setChartState } = context || EMPTY_CHART_INTEGRATION_CONTEXT; const availableChartIds = React.useMemo(() => { const ids = Object.keys(chartStateLookup); // cleanup visibleDimensions and visibleValues references Object.keys(visibleDimensions.current).forEach(chartId => { if (!ids.includes(chartId)) { delete visibleDimensions.current[chartId]; delete visibleValues.current[chartId]; } }); return ids; }, [chartStateLookup]); const syncedChartIds = React.useMemo(() => availableChartIds.filter(chartId => chartStateLookup[chartId].synced !== false), [availableChartIds, chartStateLookup]); const getColumnName = React.useCallback(field => { const customFieldName = props.slotProps?.chartsPanel?.getColumnName?.(field); if (customFieldName) { return customFieldName; } const columns = (0, _internals.gridColumnLookupSelector)(apiRef); const columnGroupPath = (0, _xDataGridPro.gridColumnGroupsUnwrappedModelSelector)(apiRef)[field] ?? []; const columnGroupLookup = (0, _xDataGridPro.gridColumnGroupsLookupSelector)(apiRef); const column = columns[field]; const columnName = column?.headerName || field; if (!pivotActive || !columnGroupPath) { return columnName; } const groupNames = columnGroupPath.map(group => columnGroupLookup[group].headerName || group); return [columnName, ...groupNames].join(' - '); }, [apiRef, pivotActive, props.slotProps?.chartsPanel]); // Adds aggregation function label to the column name const getValueDatasetLabel = React.useCallback(field => { const customFieldName = props.slotProps?.chartsPanel?.getColumnName?.(field); if (customFieldName) { return customFieldName; } const columnName = getColumnName(field); const fieldAggregation = (0, _gridAggregationSelectors.gridAggregationModelSelector)(apiRef)[field]; const suffix = fieldAggregation ? ` (${(0, _gridAggregationUtils.getAggregationFunctionLabel)({ apiRef, aggregationRule: { aggregationFunctionName: fieldAggregation, aggregationFunction: props.aggregationFunctions[fieldAggregation] || {} } })})` : ''; return `${columnName}${suffix}`; }, [apiRef, props.aggregationFunctions, props.slotProps?.chartsPanel, getColumnName]); apiRef.current.registerControlState({ stateId: 'activeChartId', propModel: props.activeChartId, propOnChange: props.onActiveChartIdChange, stateSelector: _gridChartsIntegrationSelectors.gridChartsIntegrationActiveChartIdSelector, changeEvent: 'activeChartIdChange' }); // sometimes, updates made to the chart dimensions and values require updating other models // for example, if we are adding more than one dimension, we need to set the new grouping model // if we are adding new value dataset to the grouped data, we need to set the aggregation model, otherwise the values will be undefined const updateOtherModels = React.useCallback(() => { const rowGroupingModel = (0, _gridRowGroupingSelector.gridRowGroupingSanitizedModelSelector)(apiRef); if (visibleDimensions.current[activeChartId]?.length > 0 && ( // if there was row grouping or if we are adding more than one dimension, set the new grouping model rowGroupingModel.length > 0 || visibleDimensions.current[activeChartId].length > 1) && // if row grouping model starts with dimensions in the same order, we don't have to do anything visibleDimensions.current[activeChartId].some((item, index) => item.field !== rowGroupingModel[index])) { // if pivoting is enabled, then the row grouping model is driven by the pivoting rows const newGroupingModel = visibleDimensions.current[activeChartId].map(item => item.field); if (pivotActive) { apiRef.current.setPivotModel(prev => (0, _extends2.default)({}, prev, { rows: newGroupingModel.map(item => ({ field: item, hidden: false })) })); } else { apiRef.current.setRowGroupingModel(newGroupingModel); apiRef.current.setColumnVisibilityModel((0, _extends2.default)({}, apiRef.current.state.columns.columnVisibilityModel, Object.fromEntries(rowGroupingModel.map(item => [item, true])), Object.fromEntries(newGroupingModel.map(item => [item, false])))); } } if (!pivotActive && visibleValues.current[activeChartId] && rowGroupingModel.length > 0) { // with row grouping add the aggregation model to the newly added value dataset const aggregatedFields = Object.keys(aggregationModel); const aggregationsToAdd = {}; visibleValues.current[activeChartId].forEach(item => { const hasAggregation = aggregatedFields.includes(item.field); if (!hasAggregation) { // use the first available aggregation function aggregationsToAdd[item.field] = (0, _gridAggregationUtils.getAvailableAggregationFunctions)({ aggregationFunctions: props.aggregationFunctions, colDef: item, isDataSource: !!props.dataSource })[0]; } }); if (Object.keys(aggregationsToAdd).length > 0) { apiRef.current.setAggregationModel((0, _extends2.default)({}, aggregationModel, aggregationsToAdd)); } } }, [apiRef, props.aggregationFunctions, props.dataSource, activeChartId, pivotActive, aggregationModel]); const handleRowDataUpdate = React.useCallback(chartIds => { if (chartIds.length === 0 || chartIds.some(chartId => !visibleDimensions.current[chartId] || !visibleValues.current[chartId])) { return; } const orderedFields = (0, _internals.gridColumnFieldsSelector)(apiRef); const rowGroupingModel = (0, _gridRowGroupingSelector.gridRowGroupingSanitizedModelSelector)(apiRef); const rowTree = (0, _xDataGridPro.gridRowTreeSelector)(apiRef); const rowsPerDepth = (0, _internals.gridFilteredSortedDepthRowEntriesSelector)(apiRef); const currentChartId = (0, _gridChartsIntegrationSelectors.gridChartsIntegrationActiveChartIdSelector)(apiRef); const defaultDepth = Math.max(0, (visibleDimensions.current[currentChartId]?.length ?? 0) - 1); const rowsAtDefaultDepth = (rowsPerDepth[defaultDepth] ?? []).length; // keep only unique columns and transform the grouped column to carry the correct field name to get the grouped value const dataColumns = [...new Set([...Object.values(visibleDimensions.current).flat(), ...Object.values(visibleValues.current).flat()])].map(column => { const isColumnGrouped = rowGroupingModel.includes(column.field); if (isColumnGrouped) { const groupedFieldName = isColumnGrouped ? (0, _gridRowGroupingUtils.getRowGroupingFieldFromGroupingCriteria)(orderedFields.includes(_internals.GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD) ? null : column.field) : column.field; const columnDefinition = apiRef.current.getColumn(groupedFieldName); return (0, _extends2.default)({}, columnDefinition, { dataFieldName: column.field, depth: rowGroupingModel.indexOf(column.field) }); } return (0, _extends2.default)({}, column, { dataFieldName: column.field, depth: defaultDepth }); }); // go through the data only once and collect everything that will be needed const data = Object.fromEntries(dataColumns.map(column => [column.dataFieldName, []])); const dataColumnsCount = dataColumns.length; for (let i = 0; i < rowsAtDefaultDepth; i += 1) { for (let j = 0; j < dataColumnsCount; j += 1) { // if multiple columns are grouped, we need to get the value from the parent to properly create dimension groups let targetRow = rowsPerDepth[defaultDepth][i].model; // if we are not at the same depth as the column we are currently processing change the target to the parent at the correct depth for (let d = defaultDepth; d > dataColumns[j].depth; d -= 1) { const rowId = (0, _xDataGridPro.gridRowIdSelector)(apiRef, targetRow); targetRow = (0, _xDataGridPro.gridRowNodeSelector)(apiRef, rowTree[rowId].parent); } const value = apiRef.current.getRowValue(targetRow, dataColumns[j]); if (value !== null) { data[dataColumns[j].dataFieldName].push(typeof value === 'object' && 'label' in value ? value.label : value); } } } chartIds.forEach(chartId => { setChartState(chartId, { dimensions: visibleDimensions.current[chartId].map(dimension => ({ id: dimension.field, label: getColumnName(dimension.field), data: data[dimension.field] || [] })), values: visibleValues.current[chartId].map(value => ({ id: value.field, label: getValueDatasetLabel(value.field), data: data[value.field] || [] })) }); }); }, [apiRef, getColumnName, getValueDatasetLabel, setChartState]); const debouncedHandleRowDataUpdate = React.useMemo(() => (0, _debounce.default)(handleRowDataUpdate, 0), [handleRowDataUpdate]); const handleColumnDataUpdate = React.useCallback((chartIds, updatedChartStateLookup) => { // if there are no charts, skip the data processing if (chartIds.length === 0) { return; } const rowGroupingModel = (0, _gridRowGroupingSelector.gridRowGroupingSanitizedModelSelector)(apiRef); const chartableColumns = (0, _gridChartsIntegrationSelectors.gridChartableColumnsSelector)(apiRef); const selectedFields = chartIds.reduce((acc, chartId) => { const values = (0, _gridChartsIntegrationSelectors.gridChartsValuesSelector)(apiRef, chartId); const dimensions = (0, _gridChartsIntegrationSelectors.gridChartsDimensionsSelector)(apiRef, chartId); return (0, _extends2.default)({}, acc, { [chartId]: { values, dimensions } }); }, {}); const values = {}; const dimensions = {}; chartIds.forEach(chartId => { dimensions[chartId] = []; values[chartId] = []; // loop through dimensions and values datasets either through their length or to the max limit // if the current selection is greater than the max limit, the state will be updated const chartState = updatedChartStateLookup?.[chartId] || chartStateLookup[chartId]; const dimensionsSize = chartState?.maxDimensions ? Math.min(chartState.maxDimensions, selectedFields[chartId].dimensions.length) : selectedFields[chartId].dimensions.length; const valuesSize = chartState?.maxValues ? Math.min(chartState.maxValues, selectedFields[chartId].values.length) : selectedFields[chartId].values.length; // sanitize selectedDimensions and selectedValues while maintaining their order for (let i = 0; i < valuesSize; i += 1) { if (chartableColumns[selectedFields[chartId].values[i].field] && !(0, _utils.isBlockedForSection)(chartableColumns[selectedFields[chartId].values[i].field], 'values', rowGroupingModel, pivotActive ? pivotModel : undefined)) { if (!values[chartId]) { values[chartId] = []; } values[chartId].push(selectedFields[chartId].values[i]); } } // dimensions cannot contain fields that are already in values for (let i = 0; i < dimensionsSize; i += 1) { const item = selectedFields[chartId].dimensions[i]; if (!selectedFields[chartId].values.some(valueItem => valueItem.field === item.field) && chartableColumns[item.field] && !(0, _utils.isBlockedForSection)(chartableColumns[item.field], 'dimensions', rowGroupingModel, pivotActive ? pivotModel : undefined)) { if (!dimensions[chartId]) { dimensions[chartId] = []; } dimensions[chartId].push(item); } } // we can compare the lengths, because this function is called after the state was updated. // different lengths will occur only if some items were removed during the checks above if (dimensions[chartId] && selectedFields[chartId].dimensions.length !== dimensions[chartId].length) { apiRef.current.updateChartDimensionsData(chartId, dimensions[chartId]); } if (values[chartId] && selectedFields[chartId].values.length !== values[chartId].length) { apiRef.current.updateChartValuesData(chartId, values[chartId]); } visibleDimensions.current[chartId] = dimensions[chartId].filter(dimension => dimension.hidden !== true).map(dimension => chartableColumns[dimension.field]); visibleValues.current[chartId] = values[chartId].filter(value => value.hidden !== true).map(value => chartableColumns[value.field]); // we need to have both dimensions and values to be able to display the chart if (visibleDimensions.current[chartId].length === 0 || visibleValues.current[chartId].length === 0) { visibleDimensions.current[chartId] = []; visibleValues.current[chartId] = []; } }); updateOtherModels(); debouncedHandleRowDataUpdate(chartIds); }, [apiRef, chartStateLookup, pivotActive, pivotModel, debouncedHandleRowDataUpdate, updateOtherModels]); const debouncedHandleColumnDataUpdate = React.useMemo(() => (0, _debounce.default)(handleColumnDataUpdate, 0), [handleColumnDataUpdate]); const setChartsPanelOpen = React.useCallback(callback => { if (!isChartsIntegrationAvailable) { return; } const panelOpen = (0, _gridChartsIntegrationSelectors.gridChartsPanelOpenSelector)(apiRef); const newPanelOpen = typeof callback === 'function' ? callback(panelOpen) : callback; if (panelOpen === newPanelOpen) { return; } if (newPanelOpen) { apiRef.current.showSidebar(_sidebar.GridSidebarValue.Charts); } else { apiRef.current.hideSidebar(); } }, [apiRef, isChartsIntegrationAvailable]); const updateChartDimensionsData = React.useCallback((chartId, dimensions) => { if (!isChartsIntegrationAvailable) { return; } apiRef.current.setState(state => { const newDimensions = typeof dimensions === 'function' ? dimensions(state.chartsIntegration.charts[chartId].dimensions) : dimensions; return (0, _extends2.default)({}, state, { chartsIntegration: (0, _extends2.default)({}, state.chartsIntegration, { charts: (0, _extends2.default)({}, state.chartsIntegration.charts, { [chartId]: (0, _extends2.default)({}, state.chartsIntegration.charts[chartId], { dimensions: newDimensions }) }) }) }); }); debouncedHandleColumnDataUpdate(syncedChartIds); }, [apiRef, isChartsIntegrationAvailable, syncedChartIds, debouncedHandleColumnDataUpdate]); const updateChartValuesData = React.useCallback((chartId, values) => { if (!isChartsIntegrationAvailable) { return; } apiRef.current.setState(state => { const newValues = typeof values === 'function' ? values(state.chartsIntegration.charts[chartId].values) : values; return (0, _extends2.default)({}, state, { chartsIntegration: (0, _extends2.default)({}, state.chartsIntegration, { charts: (0, _extends2.default)({}, state.chartsIntegration.charts, { [chartId]: (0, _extends2.default)({}, state.chartsIntegration.charts[chartId], { values: newValues }) }) }) }); }); debouncedHandleColumnDataUpdate(syncedChartIds); }, [apiRef, isChartsIntegrationAvailable, syncedChartIds, debouncedHandleColumnDataUpdate]); const setActiveChartId = React.useCallback(chartId => { if (!isChartsIntegrationAvailable) { return; } apiRef.current.setState(state => (0, _extends2.default)({}, state, { chartsIntegration: (0, _extends2.default)({}, state.chartsIntegration, { activeChartId: chartId }) })); }, [apiRef, isChartsIntegrationAvailable]); const setChartType = React.useCallback((chartId, type) => { if (!isChartsIntegrationAvailable || !chartStateLookup[chartId]) { return; } const stateUpdate = { type, dimensionsLabel: schema[type]?.dimensionsLabel, valuesLabel: schema[type]?.valuesLabel, maxDimensions: schema[type]?.maxDimensions, maxValues: schema[type]?.maxValues }; const updatedChartStateLookup = (0, _extends2.default)({}, chartStateLookup, { [chartId]: (0, _extends2.default)({}, chartStateLookup[chartId], stateUpdate) }); // make sure that the new dimensions and values limits are applied before changing the chart type handleColumnDataUpdate([chartId], updatedChartStateLookup); setChartState(chartId, stateUpdate); }, [isChartsIntegrationAvailable, chartStateLookup, schema, setChartState, handleColumnDataUpdate]); const setChartSynchronizationState = React.useCallback((chartId, synced) => { if (!isChartsIntegrationAvailable || !chartStateLookup[chartId]) { return; } const stateUpdate = { synced }; const updatedChartStateLookup = (0, _extends2.default)({}, chartStateLookup, { [chartId]: (0, _extends2.default)({}, chartStateLookup[chartId], stateUpdate) }); setChartState(chartId, stateUpdate); apiRef.current.publishEvent('chartSynchronizationStateChange', { chartId, synced }); if (synced) { debouncedHandleColumnDataUpdate([chartId], updatedChartStateLookup); } }, [apiRef, isChartsIntegrationAvailable, chartStateLookup, setChartState, debouncedHandleColumnDataUpdate]); // called when a column is dragged and dropped to a different section const updateDataReference = React.useCallback((field, originSection, targetSection, targetField, placementRelativeToTargetField) => { const columns = (0, _internals.gridColumnLookupSelector)(apiRef); const dimensions = (0, _gridChartsIntegrationSelectors.gridChartsDimensionsSelector)(apiRef, activeChartId); const values = (0, _gridChartsIntegrationSelectors.gridChartsValuesSelector)(apiRef, activeChartId); const rowGroupingModel = (0, _gridRowGroupingSelector.gridRowGroupingSanitizedModelSelector)(apiRef); if (targetSection) { if ((0, _utils.isBlockedForSection)(columns[field], targetSection, rowGroupingModel, pivotActive ? pivotModel : undefined)) { return; } const currentTargetItems = targetSection === 'dimensions' ? dimensions : values; const currentMaxItems = targetSection === 'dimensions' ? chartStateLookup[activeChartId]?.maxDimensions : chartStateLookup[activeChartId]?.maxValues; if (currentMaxItems && currentTargetItems.length >= currentMaxItems) { return; } } let hidden; if (originSection) { const method = originSection === 'dimensions' ? updateChartDimensionsData : updateChartValuesData; const currentItems = originSection === 'dimensions' ? [...dimensions] : [...values]; const fieldIndex = currentItems.findIndex(item => item.field === field); if (fieldIndex !== -1) { hidden = currentItems[fieldIndex].hidden; } // if the target is another section, remove the field from the origin section if (targetSection !== originSection) { currentItems.splice(fieldIndex, 1); method(activeChartId, currentItems); } } if (targetSection) { const method = targetSection === 'dimensions' ? updateChartDimensionsData : updateChartValuesData; const currentItems = targetSection === 'dimensions' ? dimensions : values; const remainingItems = targetSection === originSection ? currentItems.filter(item => item.field !== field) : [...currentItems]; // with row grouping add the aggregation model to the newly added values dataset if (rowGroupingModel.length > 0 && targetSection === 'values') { const hasAggregation = Object.keys(aggregationModel).includes(field); if (!hasAggregation) { apiRef.current.setAggregationModel((0, _extends2.default)({}, aggregationModel, { [field]: (0, _gridAggregationUtils.getAvailableAggregationFunctions)({ aggregationFunctions: props.aggregationFunctions, colDef: columns[field], isDataSource: !!props.dataSource })[0] })); } } if (targetField) { const targetFieldIndex = remainingItems.findIndex(item => item.field === targetField); const targetIndex = placementRelativeToTargetField === 'top' ? targetFieldIndex : targetFieldIndex + 1; remainingItems.splice(targetIndex, 0, { field, hidden }); method(activeChartId, remainingItems); } else { method(activeChartId, [...remainingItems, { field, hidden }]); } } }, [apiRef, props.aggregationFunctions, props.dataSource, activeChartId, chartStateLookup, updateChartDimensionsData, updateChartValuesData, aggregationModel, pivotActive, pivotModel]); const addColumnMenuButton = React.useCallback(menuItems => { if (isChartsIntegrationAvailable) { return [...menuItems, 'columnMenuManagePanelItem']; } return menuItems; }, [isChartsIntegrationAvailable]); (0, _internals.useGridRegisterPipeProcessor)(apiRef, 'columnMenu', addColumnMenuButton); const addChartsPanel = React.useCallback((initialValue, value) => { if (props.slots.chartsPanel && isChartsIntegrationAvailable && value === _sidebar.GridSidebarValue.Charts) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(props.slots.chartsPanel, (0, _extends2.default)({}, props.slotProps?.chartsPanel)); } return initialValue; }, [props, isChartsIntegrationAvailable]); (0, _internals.useGridRegisterPipeProcessor)(apiRef, 'sidebar', addChartsPanel); (0, _internals.useGridApiMethod)(apiRef, { chartsIntegration: { updateDataReference, getColumnName } }, 'private'); (0, _internals.useGridApiMethod)(apiRef, props.experimentalFeatures?.charts ? { setChartsPanelOpen, setActiveChartId, setChartType, setChartSynchronizationState, updateChartDimensionsData, updateChartValuesData } : {}, 'public'); (0, _internals.useGridEvent)(apiRef, 'columnsChange', (0, _internals.runIf)(isChartsIntegrationAvailable, () => debouncedHandleColumnDataUpdate(syncedChartIds))); (0, _internals.useGridEvent)(apiRef, 'pivotModeChange', (0, _internals.runIf)(isChartsIntegrationAvailable, () => debouncedHandleColumnDataUpdate(syncedChartIds))); (0, _internals.useGridEvent)(apiRef, 'filteredRowsSet', (0, _internals.runIf)(isChartsIntegrationAvailable, () => debouncedHandleRowDataUpdate(syncedChartIds))); (0, _internals.useGridEvent)(apiRef, 'sortedRowsSet', (0, _internals.runIf)(isChartsIntegrationAvailable, () => debouncedHandleRowDataUpdate(syncedChartIds))); (0, _internals.useGridEvent)(apiRef, 'aggregationLookupSet', (0, _internals.runIf)(isChartsIntegrationAvailable, () => debouncedHandleRowDataUpdate(syncedChartIds))); const stateExportPreProcessing = React.useCallback((prevState, exportContext) => { if (!props.chartsIntegration || !props.experimentalFeatures?.charts) { return prevState; } const currentActiveChartId = (0, _gridChartsIntegrationSelectors.gridChartsIntegrationActiveChartIdSelector)(apiRef); const chartsLookup = (0, _gridChartsIntegrationSelectors.gridChartsIntegrationChartsLookupSelector)(apiRef); const integrationContextToExport = Object.fromEntries(Object.entries(chartStateLookup).map(([chartId, chartState]) => [chartId, // keep only the state that is controlled by the user, drop the data and labels { synced: chartState.synced, type: chartState.type, configuration: chartState.configuration }])); const shouldExportChartState = // Always export if the `exportOnlyDirtyModels` property is not activated !exportContext.exportOnlyDirtyModels || // Always export if the chart state has been initialized props.initialState?.chartsIntegration != null || // Export if the chart model or context is not empty Object.keys(chartsLookup).length > 0 || Object.keys(integrationContextToExport).length > 0; if (!shouldExportChartState) { return prevState; } const chartStateToExport = { activeChartId: currentActiveChartId, charts: chartsLookup, // add a custom prop to keep the integration context in the exported state integrationContext: integrationContextToExport }; return (0, _extends2.default)({}, prevState, { chartsIntegration: chartStateToExport }); }, [apiRef, chartStateLookup, props.chartsIntegration, props.experimentalFeatures?.charts, props.initialState?.chartsIntegration]); const stateRestorePreProcessing = React.useCallback((params, restoreContext) => { const chartsRestoreState = restoreContext.stateToRestore.chartsIntegration; if (!chartsRestoreState) { return params; } const { activeChartId: activeChartIdToRestore, charts: chartsToRestore, integrationContext } = chartsRestoreState; if (activeChartIdToRestore === undefined || chartsToRestore === undefined || Object.keys(chartsToRestore).length === 0) { return params; } apiRef.current.setState((0, _extends2.default)({}, apiRef.current.state, { chartsIntegration: { activeChartId: activeChartIdToRestore, charts: chartsToRestore } })); // restore the integration context for each chart Object.entries(integrationContext).forEach(([chartId, chartContextState]) => { setChartState(chartId, chartContextState); }); return params; }, [apiRef, setChartState]); (0, _internals.useGridRegisterPipeProcessor)(apiRef, 'exportState', stateExportPreProcessing); (0, _internals.useGridRegisterPipeProcessor)(apiRef, 'restoreState', stateRestorePreProcessing); React.useEffect(() => { if (!activeChartId && availableChartIds.length > 0) { setActiveChartId(availableChartIds[0]); } }, [availableChartIds, activeChartId, setActiveChartId]); const isInitialized = React.useRef(false); React.useEffect(() => { if (isInitialized.current) { return; } if (availableChartIds.length === 0) { return; } isInitialized.current = true; availableChartIds.forEach(chartId => { const chartType = props.initialState?.chartsIntegration?.charts?.[chartId]?.chartType || ''; setChartState(chartId, { type: chartType, maxDimensions: schema[chartType]?.maxDimensions, maxValues: schema[chartType]?.maxValues, dimensionsLabel: schema[chartType]?.dimensionsLabel, valuesLabel: schema[chartType]?.valuesLabel, configuration: props.initialState?.chartsIntegration?.charts?.[chartId]?.configuration || {} }); }); debouncedHandleColumnDataUpdate(syncedChartIds); }, [schema, availableChartIds, syncedChartIds, props.initialState?.chartsIntegration?.charts, setChartState, debouncedHandleColumnDataUpdate]); }; exports.useGridChartsIntegration = useGridChartsIntegration;