@mui/x-data-grid-premium 8.11.2 → 8.12.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 +231 -0
- package/DataGridPremium/DataGridPremium.js +29 -1
- package/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
- package/DataGridPremium/useDataGridPremiumComponent.js +5 -2
- package/DataGridPremium/useDataGridPremiumProps.js +2 -1
- package/components/GridPremiumColumnMenu.d.ts +4 -4
- package/components/GridPremiumColumnMenu.js +6 -6
- package/components/GridPremiumToolbar.js +11 -0
- package/components/chartsIntegration/GridChartsIntegrationContext.d.ts +2 -0
- package/components/chartsIntegration/GridChartsIntegrationContext.js +11 -0
- package/components/chartsPanel/ChartsPanelTrigger.d.ts +33 -0
- package/components/chartsPanel/ChartsPanelTrigger.js +92 -0
- package/components/chartsPanel/GridChartsPanel.d.ts +21 -0
- package/components/chartsPanel/GridChartsPanel.js +243 -0
- package/components/chartsPanel/chart/GridChartsPanelChart.d.ts +12 -0
- package/components/chartsPanel/chart/GridChartsPanelChart.js +111 -0
- package/components/chartsPanel/customize/GridChartsPanelCustomize.d.ts +8 -0
- package/components/chartsPanel/customize/GridChartsPanelCustomize.js +147 -0
- package/components/chartsPanel/data/GridChartsPanelData.d.ts +4 -0
- package/components/chartsPanel/data/GridChartsPanelData.js +23 -0
- package/components/chartsPanel/data/GridChartsPanelDataBody.d.ts +12 -0
- package/components/chartsPanel/data/GridChartsPanelDataBody.js +380 -0
- package/components/chartsPanel/data/GridChartsPanelDataField.d.ts +25 -0
- package/components/chartsPanel/data/GridChartsPanelDataField.js +334 -0
- package/components/chartsPanel/data/GridChartsPanelDataFieldMenu.d.ts +11 -0
- package/components/chartsPanel/data/GridChartsPanelDataFieldMenu.js +179 -0
- package/components/chartsPanel/data/GridChartsPanelDataHeader.d.ts +7 -0
- package/components/chartsPanel/data/GridChartsPanelDataHeader.js +24 -0
- package/components/chartsPanel/data/GridChartsPanelDataSearch.d.ts +7 -0
- package/components/chartsPanel/data/GridChartsPanelDataSearch.js +80 -0
- package/components/chartsPanel/index.d.ts +2 -0
- package/components/chartsPanel/index.js +27 -0
- package/components/collapsible/Collapsible.d.ts +3 -1
- package/components/collapsible/Collapsible.js +4 -3
- package/components/{GridColumnMenuAggregationItem.js → columnMenu/menuItems/GridColumnMenuAggregationItem.js} +4 -4
- package/components/columnMenu/menuItems/GridColumnMenuChartsItem.d.ts +3 -0
- package/components/columnMenu/menuItems/GridColumnMenuChartsItem.js +36 -0
- package/components/columnMenu/menuItems/GridColumnMenuManagePanelItem.d.ts +4 -0
- package/components/columnMenu/menuItems/GridColumnMenuManagePanelItem.js +18 -0
- package/{esm/components → components/columnMenu/menuItems}/GridColumnMenuPivotItem.d.ts +1 -1
- package/components/{GridColumnMenuPivotItem.js → columnMenu/menuItems/GridColumnMenuPivotItem.js} +7 -4
- package/components/{GridColumnMenuRowGroupItem.js → columnMenu/menuItems/GridColumnMenuRowGroupItem.js} +4 -4
- package/components/{GridColumnMenuRowUngroupItem.js → columnMenu/menuItems/GridColumnMenuRowUngroupItem.js} +3 -3
- package/components/index.d.ts +3 -2
- package/components/index.js +13 -1
- package/components/pivotPanel/GridPivotPanelField.js +14 -2
- package/components/pivotPanel/GridPivotPanelHeader.js +1 -0
- package/components/pivotPanel/GridPivotPanelSearch.js +3 -0
- package/components/promptField/PromptFieldControl.js +1 -1
- package/constants/columnGroups.d.ts +1 -0
- package/constants/columnGroups.js +7 -0
- package/constants/dataGridPremiumDefaultSlotsComponents.js +1 -0
- package/context/GridChartsIntegrationContextProvider.d.ts +7 -0
- package/context/GridChartsIntegrationContextProvider.js +35 -0
- package/context/GridChartsRendererProxy.d.ts +34 -0
- package/context/GridChartsRendererProxy.js +77 -0
- package/context/index.d.ts +2 -0
- package/context/index.js +27 -0
- package/esm/DataGridPremium/DataGridPremium.js +30 -2
- package/esm/DataGridPremium/useDataGridPremiumComponent.d.ts +1 -1
- package/esm/DataGridPremium/useDataGridPremiumComponent.js +5 -2
- package/esm/DataGridPremium/useDataGridPremiumProps.js +2 -1
- package/esm/components/GridPremiumColumnMenu.d.ts +4 -4
- package/esm/components/GridPremiumColumnMenu.js +6 -6
- package/esm/components/GridPremiumToolbar.js +11 -0
- package/esm/components/chartsIntegration/GridChartsIntegrationContext.d.ts +2 -0
- package/esm/components/chartsIntegration/GridChartsIntegrationContext.js +5 -0
- package/esm/components/chartsPanel/ChartsPanelTrigger.d.ts +33 -0
- package/esm/components/chartsPanel/ChartsPanelTrigger.js +85 -0
- package/esm/components/chartsPanel/GridChartsPanel.d.ts +21 -0
- package/esm/components/chartsPanel/GridChartsPanel.js +237 -0
- package/esm/components/chartsPanel/chart/GridChartsPanelChart.d.ts +12 -0
- package/esm/components/chartsPanel/chart/GridChartsPanelChart.js +104 -0
- package/esm/components/chartsPanel/customize/GridChartsPanelCustomize.d.ts +8 -0
- package/esm/components/chartsPanel/customize/GridChartsPanelCustomize.js +139 -0
- package/esm/components/chartsPanel/data/GridChartsPanelData.d.ts +4 -0
- package/esm/components/chartsPanel/data/GridChartsPanelData.js +18 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataBody.d.ts +12 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataBody.js +374 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataField.d.ts +25 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataField.js +327 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataFieldMenu.d.ts +11 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataFieldMenu.js +173 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataHeader.d.ts +7 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataHeader.js +18 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataSearch.d.ts +7 -0
- package/esm/components/chartsPanel/data/GridChartsPanelDataSearch.js +73 -0
- package/esm/components/chartsPanel/index.d.ts +2 -0
- package/esm/components/chartsPanel/index.js +2 -0
- package/esm/components/collapsible/Collapsible.d.ts +3 -1
- package/esm/components/collapsible/Collapsible.js +4 -3
- package/esm/components/{GridColumnMenuAggregationItem.js → columnMenu/menuItems/GridColumnMenuAggregationItem.js} +4 -4
- package/esm/components/columnMenu/menuItems/GridColumnMenuChartsItem.d.ts +3 -0
- package/esm/components/columnMenu/menuItems/GridColumnMenuChartsItem.js +29 -0
- package/esm/components/columnMenu/menuItems/GridColumnMenuManagePanelItem.d.ts +4 -0
- package/esm/components/columnMenu/menuItems/GridColumnMenuManagePanelItem.js +11 -0
- package/{components → esm/components/columnMenu/menuItems}/GridColumnMenuPivotItem.d.ts +1 -1
- package/esm/components/{GridColumnMenuPivotItem.js → columnMenu/menuItems/GridColumnMenuPivotItem.js} +7 -4
- package/esm/components/{GridColumnMenuRowGroupItem.js → columnMenu/menuItems/GridColumnMenuRowGroupItem.js} +4 -4
- package/esm/components/{GridColumnMenuRowUngroupItem.js → columnMenu/menuItems/GridColumnMenuRowUngroupItem.js} +3 -3
- package/esm/components/index.d.ts +3 -2
- package/esm/components/index.js +3 -2
- package/esm/components/pivotPanel/GridPivotPanelField.js +15 -3
- package/esm/components/pivotPanel/GridPivotPanelHeader.js +1 -0
- package/esm/components/pivotPanel/GridPivotPanelSearch.js +3 -0
- package/esm/components/promptField/PromptFieldControl.js +1 -1
- package/esm/constants/columnGroups.d.ts +1 -0
- package/esm/constants/columnGroups.js +1 -0
- package/esm/constants/dataGridPremiumDefaultSlotsComponents.js +1 -0
- package/esm/context/GridChartsIntegrationContextProvider.d.ts +7 -0
- package/esm/context/GridChartsIntegrationContextProvider.js +28 -0
- package/esm/context/GridChartsRendererProxy.d.ts +34 -0
- package/esm/context/GridChartsRendererProxy.js +71 -0
- package/esm/context/index.d.ts +2 -0
- package/esm/context/index.js +2 -0
- package/esm/hooks/features/aggregation/createAggregationLookup.js +5 -3
- package/esm/hooks/features/aggregation/gridAggregationInterfaces.d.ts +1 -0
- package/esm/hooks/features/aggregation/gridAggregationSelectors.d.ts +1 -0
- package/esm/hooks/features/aggregation/gridAggregationSelectors.js +3 -0
- package/esm/hooks/features/aggregation/useGridAggregation.js +13 -1
- package/esm/hooks/features/aggregation/wrapColumnWithAggregation.d.ts +2 -1
- package/esm/hooks/features/aggregation/wrapColumnWithAggregation.js +1 -45
- package/esm/hooks/features/chartsIntegration/gridChartsIntegrationInterfaces.d.ts +65 -0
- package/esm/hooks/features/chartsIntegration/gridChartsIntegrationInterfaces.js +1 -0
- package/esm/hooks/features/chartsIntegration/gridChartsIntegrationSelectors.d.ts +17 -0
- package/esm/hooks/features/chartsIntegration/gridChartsIntegrationSelectors.js +24 -0
- package/esm/hooks/features/chartsIntegration/useGridChartsIntegration.d.ts +8 -0
- package/esm/hooks/features/chartsIntegration/useGridChartsIntegration.js +525 -0
- package/esm/hooks/features/chartsIntegration/utils.d.ts +5 -0
- package/esm/hooks/features/chartsIntegration/utils.js +32 -0
- package/esm/hooks/features/pivoting/useGridPivoting.js +1 -1
- package/esm/hooks/features/pivoting/utils.js +9 -7
- package/esm/hooks/features/rowGrouping/createGroupingColDef.js +3 -1
- package/esm/hooks/features/rowGrouping/gridRowGroupingUtils.d.ts +1 -0
- package/esm/hooks/features/rowGrouping/gridRowGroupingUtils.js +3 -2
- package/esm/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +1 -0
- package/esm/hooks/features/sidebar/gridSidebarInterfaces.d.ts +1 -0
- package/esm/hooks/features/sidebar/gridSidebarInterfaces.js +1 -0
- package/esm/hooks/utils/index.d.ts +2 -1
- package/esm/hooks/utils/index.js +2 -1
- package/esm/hooks/utils/useGridChartIntegration.d.ts +2 -0
- package/esm/hooks/utils/useGridChartIntegration.js +9 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +2 -1
- package/esm/material/icons.d.ts +4 -1
- package/esm/material/icons.js +16 -2
- package/esm/material/index.d.ts +11 -0
- package/esm/material/index.js +13 -2
- package/esm/models/dataGridPremiumProps.d.ts +22 -1
- package/esm/models/gridApiPremium.d.ts +3 -2
- package/esm/models/gridChartsIntegration.d.ts +17 -0
- package/esm/models/gridChartsIntegration.js +1 -0
- package/esm/models/gridPremiumIconSlotsComponent.d.ts +55 -0
- package/esm/models/gridPremiumSlotProps.d.ts +8 -0
- package/esm/models/gridPremiumSlotProps.js +1 -0
- package/esm/models/gridPremiumSlotsComponent.d.ts +6 -0
- package/esm/models/gridStatePremium.d.ts +5 -2
- package/esm/typeOverloads/modules.d.ts +20 -0
- package/hooks/features/aggregation/createAggregationLookup.js +5 -3
- package/hooks/features/aggregation/gridAggregationInterfaces.d.ts +1 -0
- package/hooks/features/aggregation/gridAggregationSelectors.d.ts +1 -0
- package/hooks/features/aggregation/gridAggregationSelectors.js +3 -0
- package/hooks/features/aggregation/useGridAggregation.js +12 -0
- package/hooks/features/aggregation/wrapColumnWithAggregation.d.ts +2 -1
- package/hooks/features/aggregation/wrapColumnWithAggregation.js +0 -44
- package/hooks/features/chartsIntegration/gridChartsIntegrationInterfaces.d.ts +65 -0
- package/hooks/features/chartsIntegration/gridChartsIntegrationInterfaces.js +5 -0
- package/hooks/features/chartsIntegration/gridChartsIntegrationSelectors.d.ts +17 -0
- package/hooks/features/chartsIntegration/gridChartsIntegrationSelectors.js +30 -0
- package/hooks/features/chartsIntegration/useGridChartsIntegration.d.ts +8 -0
- package/hooks/features/chartsIntegration/useGridChartsIntegration.js +534 -0
- package/hooks/features/chartsIntegration/utils.d.ts +5 -0
- package/hooks/features/chartsIntegration/utils.js +40 -0
- package/hooks/features/pivoting/useGridPivoting.js +1 -1
- package/hooks/features/pivoting/utils.js +9 -7
- package/hooks/features/rowGrouping/createGroupingColDef.js +3 -1
- package/hooks/features/rowGrouping/gridRowGroupingUtils.d.ts +1 -0
- package/hooks/features/rowGrouping/gridRowGroupingUtils.js +3 -2
- package/hooks/features/rowGrouping/useGridRowGroupingPreProcessors.js +1 -0
- package/hooks/features/sidebar/gridSidebarInterfaces.d.ts +1 -0
- package/hooks/features/sidebar/gridSidebarInterfaces.js +1 -0
- package/hooks/utils/index.d.ts +2 -1
- package/hooks/utils/index.js +11 -0
- package/hooks/utils/useGridChartIntegration.d.ts +2 -0
- package/hooks/utils/useGridChartIntegration.js +17 -0
- package/index.d.ts +1 -0
- package/index.js +13 -1
- package/material/icons.d.ts +4 -1
- package/material/icons.js +16 -2
- package/material/index.d.ts +11 -0
- package/material/index.js +12 -1
- package/models/dataGridPremiumProps.d.ts +22 -1
- package/models/gridApiPremium.d.ts +3 -2
- package/models/gridChartsIntegration.d.ts +17 -0
- package/models/gridChartsIntegration.js +5 -0
- package/models/gridPremiumIconSlotsComponent.d.ts +55 -0
- package/models/gridPremiumSlotProps.d.ts +8 -0
- package/models/gridPremiumSlotProps.js +5 -0
- package/models/gridPremiumSlotsComponent.d.ts +6 -0
- package/models/gridStatePremium.d.ts +5 -2
- package/package.json +5 -5
- package/typeOverloads/modules.d.ts +20 -0
- /package/components/{GridColumnMenuAggregationItem.d.ts → columnMenu/menuItems/GridColumnMenuAggregationItem.d.ts} +0 -0
- /package/components/{GridColumnMenuRowGroupItem.d.ts → columnMenu/menuItems/GridColumnMenuRowGroupItem.d.ts} +0 -0
- /package/components/{GridColumnMenuRowUngroupItem.d.ts → columnMenu/menuItems/GridColumnMenuRowUngroupItem.d.ts} +0 -0
- /package/esm/components/{GridColumnMenuAggregationItem.d.ts → columnMenu/menuItems/GridColumnMenuAggregationItem.d.ts} +0 -0
- /package/esm/components/{GridColumnMenuRowGroupItem.d.ts → columnMenu/menuItems/GridColumnMenuRowGroupItem.d.ts} +0 -0
- /package/esm/components/{GridColumnMenuRowUngroupItem.d.ts → columnMenu/menuItems/GridColumnMenuRowUngroupItem.d.ts} +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createRootSelector, createSelector, createSelectorMemoized, gridColumnLookupSelector, gridPivotActiveSelector } from '@mui/x-data-grid-pro/internals';
|
|
2
|
+
import { gridSidebarStateSelector, GridSidebarValue } from "../sidebar/index.js";
|
|
3
|
+
import { gridPivotModelSelector } from "../pivoting/gridPivotingSelectors.js";
|
|
4
|
+
const gridChartsIntegrationStateSelector = createRootSelector(state => state.chartsIntegration);
|
|
5
|
+
export const gridChartsIntegrationActiveChartIdSelector = createSelector(gridChartsIntegrationStateSelector, chartsIntegration => chartsIntegration.activeChartId);
|
|
6
|
+
export const gridChartsPanelOpenSelector = createSelector(gridSidebarStateSelector, sidebar => sidebar.value === GridSidebarValue.Charts && sidebar.open);
|
|
7
|
+
export const gridChartableColumnsSelector = createSelectorMemoized(gridColumnLookupSelector, gridPivotActiveSelector, gridPivotModelSelector, (columns, pivotActive, pivotModel) => {
|
|
8
|
+
let chartableColumns = Object.values(columns).filter(column => column.chartable);
|
|
9
|
+
if (pivotActive) {
|
|
10
|
+
const pivotColumns = pivotModel.columns.filter(column => column.hidden !== true).map(column => column.field);
|
|
11
|
+
const pivotValues = pivotModel.values.filter(value => value.hidden !== true).map(value => value.field);
|
|
12
|
+
// pivot columns are not visualized
|
|
13
|
+
// once the columns are set, value fields are created dynamically. those fields remain chartable, but we remove the initial value columns
|
|
14
|
+
if (pivotColumns.length > 0) {
|
|
15
|
+
chartableColumns = chartableColumns.filter(column => !pivotColumns.includes(column.field) && !pivotValues.includes(column.field));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return chartableColumns.reduce((acc, column) => {
|
|
19
|
+
acc[column.field] = column;
|
|
20
|
+
return acc;
|
|
21
|
+
}, {});
|
|
22
|
+
});
|
|
23
|
+
export const gridChartsDimensionsSelector = createSelector(gridChartsIntegrationStateSelector, (chartsIntegration, chartId) => chartsIntegration.charts[chartId]?.dimensions || []);
|
|
24
|
+
export const gridChartsValuesSelector = createSelector(gridChartsIntegrationStateSelector, (chartsIntegration, chartId) => chartsIntegration.charts[chartId]?.values || []);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RefObject } from '@mui/x-internals/types';
|
|
2
|
+
import { GridStateInitializer } from '@mui/x-data-grid-pro/internals';
|
|
3
|
+
import type { DataGridPremiumProcessedProps } from "../../../models/dataGridPremiumProps.js";
|
|
4
|
+
import { GridPrivateApiPremium } from "../../../models/gridApiPremium.js";
|
|
5
|
+
import { ChartState } from "../../../models/gridChartsIntegration.js";
|
|
6
|
+
export declare const chartsIntegrationStateInitializer: GridStateInitializer<Pick<DataGridPremiumProcessedProps, 'chartsIntegration' | 'initialState' | 'activeChartId' | 'rowGroupingModel' | 'pivotModel' | 'experimentalFeatures'>, GridPrivateApiPremium>;
|
|
7
|
+
export declare const EMPTY_CHART_INTEGRATION_CONTEXT_STATE: ChartState;
|
|
8
|
+
export declare const useGridChartsIntegration: (apiRef: RefObject<GridPrivateApiPremium>, props: Pick<DataGridPremiumProcessedProps, "chartsIntegration" | "activeChartId" | "onActiveChartIdChange" | "initialState" | "slots" | "slotProps" | "aggregationFunctions" | "dataSource" | "experimentalFeatures">) => void;
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import debounce from '@mui/utils/debounce';
|
|
6
|
+
import { gridColumnGroupsLookupSelector, gridColumnGroupsUnwrappedModelSelector, gridRowIdSelector, gridRowNodeSelector, gridRowTreeSelector } from '@mui/x-data-grid-pro';
|
|
7
|
+
import { useGridApiMethod, useGridEvent, gridColumnLookupSelector, runIf, gridPivotActiveSelector, useGridRegisterPipeProcessor, gridColumnFieldsSelector, gridFilteredSortedDepthRowEntriesSelector, GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD } from '@mui/x-data-grid-pro/internals';
|
|
8
|
+
import { getRowGroupingFieldFromGroupingCriteria } from "../rowGrouping/gridRowGroupingUtils.js";
|
|
9
|
+
import { gridChartsPanelOpenSelector, gridChartsDimensionsSelector, gridChartsValuesSelector, gridChartsIntegrationActiveChartIdSelector, gridChartableColumnsSelector } from "./gridChartsIntegrationSelectors.js";
|
|
10
|
+
import { useGridChartsIntegrationContext } from "../../utils/useGridChartIntegration.js";
|
|
11
|
+
import { isBlockedForSection } from "./utils.js";
|
|
12
|
+
import { gridRowGroupingSanitizedModelSelector } from "../rowGrouping/gridRowGroupingSelector.js";
|
|
13
|
+
import { GridSidebarValue } from "../sidebar/index.js";
|
|
14
|
+
import { getAggregationFunctionLabel, getAvailableAggregationFunctions } from "../aggregation/gridAggregationUtils.js";
|
|
15
|
+
import { gridAggregationModelSelector } from "../aggregation/gridAggregationSelectors.js";
|
|
16
|
+
import { gridPivotModelSelector } from "../pivoting/gridPivotingSelectors.js";
|
|
17
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
|
+
export const chartsIntegrationStateInitializer = (state, props) => {
|
|
19
|
+
if (!props.chartsIntegration || !props.experimentalFeatures?.charts) {
|
|
20
|
+
return _extends({}, state, {
|
|
21
|
+
chartsIntegration: {
|
|
22
|
+
activeChartId: '',
|
|
23
|
+
charts: {}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
const rowGroupingModel = (state.rowGrouping?.model ?? []).filter(item => item !== undefined);
|
|
28
|
+
const pivotModel = state.pivoting?.active ? state.pivoting?.model : undefined;
|
|
29
|
+
const columnsLookup = state.columns?.lookup ?? {};
|
|
30
|
+
const charts = Object.fromEntries(Object.entries(props.initialState?.chartsIntegration?.charts || {}).map(([chartId, chart]) => [chartId, {
|
|
31
|
+
dimensions: (chart.dimensions || []).map(dimension => typeof dimension === 'string' ? {
|
|
32
|
+
field: dimension,
|
|
33
|
+
hidden: false
|
|
34
|
+
} : dimension).filter(dimension => columnsLookup[dimension.field]?.chartable === true && !isBlockedForSection(columnsLookup[dimension.field], 'dimensions', rowGroupingModel, pivotModel)),
|
|
35
|
+
values: (chart.values || []).map(value => typeof value === 'string' ? {
|
|
36
|
+
field: value,
|
|
37
|
+
hidden: false
|
|
38
|
+
} : value).filter(value => columnsLookup[value.field]?.chartable === true && !isBlockedForSection(columnsLookup[value.field], 'values', rowGroupingModel, pivotModel))
|
|
39
|
+
}]));
|
|
40
|
+
return _extends({}, state, {
|
|
41
|
+
chartsIntegration: {
|
|
42
|
+
activeChartId: props.activeChartId ?? props.initialState?.chartsIntegration?.activeChartId ?? '',
|
|
43
|
+
charts
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const EMPTY_CHART_INTEGRATION_CONTEXT = {
|
|
48
|
+
chartStateLookup: {},
|
|
49
|
+
setChartState: () => {}
|
|
50
|
+
};
|
|
51
|
+
export const EMPTY_CHART_INTEGRATION_CONTEXT_STATE = {
|
|
52
|
+
synced: true,
|
|
53
|
+
dimensions: [],
|
|
54
|
+
values: [],
|
|
55
|
+
type: '',
|
|
56
|
+
configuration: {}
|
|
57
|
+
};
|
|
58
|
+
export const useGridChartsIntegration = (apiRef, props) => {
|
|
59
|
+
const visibleDimensions = React.useRef({});
|
|
60
|
+
const visibleValues = React.useRef({});
|
|
61
|
+
const schema = React.useMemo(() => props.slotProps?.chartsPanel?.schema || {}, [props.slotProps?.chartsPanel?.schema]);
|
|
62
|
+
const context = useGridChartsIntegrationContext(true);
|
|
63
|
+
const isChartsIntegrationAvailable = !!props.chartsIntegration && !!props.experimentalFeatures?.charts && !!context;
|
|
64
|
+
const activeChartId = gridChartsIntegrationActiveChartIdSelector(apiRef);
|
|
65
|
+
const orderedFields = gridColumnFieldsSelector(apiRef);
|
|
66
|
+
const aggregationModel = gridAggregationModelSelector(apiRef);
|
|
67
|
+
const pivotActive = gridPivotActiveSelector(apiRef);
|
|
68
|
+
const pivotModel = gridPivotModelSelector(apiRef);
|
|
69
|
+
const {
|
|
70
|
+
chartStateLookup,
|
|
71
|
+
setChartState
|
|
72
|
+
} = context || EMPTY_CHART_INTEGRATION_CONTEXT;
|
|
73
|
+
const availableChartIds = React.useMemo(() => {
|
|
74
|
+
const ids = Object.keys(chartStateLookup);
|
|
75
|
+
// cleanup visibleDimensions and visibleValues references
|
|
76
|
+
Object.keys(visibleDimensions.current).forEach(chartId => {
|
|
77
|
+
if (!ids.includes(chartId)) {
|
|
78
|
+
delete visibleDimensions.current[chartId];
|
|
79
|
+
delete visibleValues.current[chartId];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return ids;
|
|
83
|
+
}, [chartStateLookup]);
|
|
84
|
+
const syncedChartIds = React.useMemo(() => availableChartIds.filter(chartId => chartStateLookup[chartId].synced !== false), [availableChartIds, chartStateLookup]);
|
|
85
|
+
const getColumnName = React.useCallback(field => {
|
|
86
|
+
const customFieldName = props.slotProps?.chartsPanel?.getColumnName?.(field);
|
|
87
|
+
if (customFieldName) {
|
|
88
|
+
return customFieldName;
|
|
89
|
+
}
|
|
90
|
+
const columns = gridColumnLookupSelector(apiRef);
|
|
91
|
+
const columnGroupPath = gridColumnGroupsUnwrappedModelSelector(apiRef)[field] ?? [];
|
|
92
|
+
const columnGroupLookup = gridColumnGroupsLookupSelector(apiRef);
|
|
93
|
+
const column = columns[field];
|
|
94
|
+
const columnName = column?.headerName || field;
|
|
95
|
+
if (!pivotActive || !columnGroupPath) {
|
|
96
|
+
return columnName;
|
|
97
|
+
}
|
|
98
|
+
const groupNames = columnGroupPath.map(group => columnGroupLookup[group].headerName || group);
|
|
99
|
+
return [columnName, ...groupNames].join(' - ');
|
|
100
|
+
}, [apiRef, pivotActive, props.slotProps?.chartsPanel]);
|
|
101
|
+
|
|
102
|
+
// Adds aggregation function label to the column name
|
|
103
|
+
const getValueDatasetLabel = React.useCallback(field => {
|
|
104
|
+
const customFieldName = props.slotProps?.chartsPanel?.getColumnName?.(field);
|
|
105
|
+
if (customFieldName) {
|
|
106
|
+
return customFieldName;
|
|
107
|
+
}
|
|
108
|
+
const columnName = getColumnName(field);
|
|
109
|
+
const fieldAggregation = gridAggregationModelSelector(apiRef)[field];
|
|
110
|
+
const suffix = fieldAggregation ? ` (${getAggregationFunctionLabel({
|
|
111
|
+
apiRef,
|
|
112
|
+
aggregationRule: {
|
|
113
|
+
aggregationFunctionName: fieldAggregation,
|
|
114
|
+
aggregationFunction: props.aggregationFunctions[fieldAggregation] || {}
|
|
115
|
+
}
|
|
116
|
+
})})` : '';
|
|
117
|
+
return `${columnName}${suffix}`;
|
|
118
|
+
}, [apiRef, props.aggregationFunctions, props.slotProps?.chartsPanel, getColumnName]);
|
|
119
|
+
apiRef.current.registerControlState({
|
|
120
|
+
stateId: 'activeChartId',
|
|
121
|
+
propModel: props.activeChartId,
|
|
122
|
+
propOnChange: props.onActiveChartIdChange,
|
|
123
|
+
stateSelector: gridChartsIntegrationActiveChartIdSelector,
|
|
124
|
+
changeEvent: 'activeChartIdChange'
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// sometimes, updates made to the chart dimensions and values require updating other models
|
|
128
|
+
// for example, if we are adding more than one dimension, we need to set the new grouping model
|
|
129
|
+
// if we are adding new value dataset to the grouped data, we need to set the aggregation model, otherwise the values will be undefined
|
|
130
|
+
const updateOtherModels = React.useCallback(() => {
|
|
131
|
+
const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
|
|
132
|
+
if (visibleDimensions.current[activeChartId]?.length > 0 && (
|
|
133
|
+
// if there was row grouping or if we are adding more than one dimension, set the new grouping model
|
|
134
|
+
rowGroupingModel.length > 0 || visibleDimensions.current[activeChartId].length > 1) &&
|
|
135
|
+
// if row grouping model starts with dimensions in the same order, we don't have to do anything
|
|
136
|
+
visibleDimensions.current[activeChartId].some((item, index) => item.field !== rowGroupingModel[index])) {
|
|
137
|
+
// if pivoting is enabled, then the row grouping model is driven by the pivoting rows
|
|
138
|
+
const newGroupingModel = visibleDimensions.current[activeChartId].map(item => item.field);
|
|
139
|
+
if (pivotActive) {
|
|
140
|
+
apiRef.current.setPivotModel(prev => _extends({}, prev, {
|
|
141
|
+
rows: newGroupingModel.map(item => ({
|
|
142
|
+
field: item,
|
|
143
|
+
hidden: false
|
|
144
|
+
}))
|
|
145
|
+
}));
|
|
146
|
+
} else {
|
|
147
|
+
apiRef.current.setRowGroupingModel(newGroupingModel);
|
|
148
|
+
apiRef.current.setColumnVisibilityModel(_extends({}, apiRef.current.state.columns.columnVisibilityModel, Object.fromEntries(rowGroupingModel.map(item => [item, true])), Object.fromEntries(newGroupingModel.map(item => [item, false]))));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!pivotActive && visibleValues.current[activeChartId] && rowGroupingModel.length > 0) {
|
|
152
|
+
// with row grouping add the aggregation model to the newly added value dataset
|
|
153
|
+
const aggregatedFields = Object.keys(aggregationModel);
|
|
154
|
+
visibleValues.current[activeChartId].forEach(item => {
|
|
155
|
+
const hasAggregation = aggregatedFields.includes(item.field);
|
|
156
|
+
if (!hasAggregation) {
|
|
157
|
+
apiRef.current.setAggregationModel(_extends({}, aggregationModel, {
|
|
158
|
+
// use the first available aggregation function
|
|
159
|
+
[item.field]: getAvailableAggregationFunctions({
|
|
160
|
+
aggregationFunctions: props.aggregationFunctions,
|
|
161
|
+
colDef: item,
|
|
162
|
+
isDataSource: !!props.dataSource
|
|
163
|
+
})[0]
|
|
164
|
+
}));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}, [apiRef, props.aggregationFunctions, props.dataSource, activeChartId, pivotActive, aggregationModel]);
|
|
169
|
+
const handleRowDataUpdate = React.useCallback(chartIds => {
|
|
170
|
+
if (chartIds.length === 0 || chartIds.some(chartId => !visibleDimensions.current[chartId] || !visibleValues.current[chartId])) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
|
|
174
|
+
const rowTree = gridRowTreeSelector(apiRef);
|
|
175
|
+
const rowsPerDepth = gridFilteredSortedDepthRowEntriesSelector(apiRef);
|
|
176
|
+
const defaultDepth = Math.max(0, (visibleDimensions.current[activeChartId]?.length ?? 0) - 1);
|
|
177
|
+
const rowsAtDefaultDepth = (rowsPerDepth[defaultDepth] ?? []).length;
|
|
178
|
+
|
|
179
|
+
// keep only unique columns and transform the grouped column to carry the correct field name to get the grouped value
|
|
180
|
+
const dataColumns = [...new Set([...Object.values(visibleDimensions.current).flat(), ...Object.values(visibleValues.current).flat()])].map(column => {
|
|
181
|
+
const isColumnGrouped = rowGroupingModel.includes(column.field);
|
|
182
|
+
if (isColumnGrouped) {
|
|
183
|
+
const groupedFieldName = isColumnGrouped ? getRowGroupingFieldFromGroupingCriteria(orderedFields.includes(GRID_ROW_GROUPING_SINGLE_GROUPING_FIELD) ? null : column.field) : column.field;
|
|
184
|
+
const columnDefinition = apiRef.current.getColumn(groupedFieldName);
|
|
185
|
+
return _extends({}, columnDefinition, {
|
|
186
|
+
dataFieldName: column.field,
|
|
187
|
+
depth: rowGroupingModel.indexOf(column.field)
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return _extends({}, column, {
|
|
191
|
+
dataFieldName: column.field,
|
|
192
|
+
depth: defaultDepth
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// go through the data only once and collect everything that will be needed
|
|
197
|
+
const data = Object.fromEntries(dataColumns.map(column => [column.dataFieldName, []]));
|
|
198
|
+
const dataColumnsCount = dataColumns.length;
|
|
199
|
+
for (let i = 0; i < rowsAtDefaultDepth; i += 1) {
|
|
200
|
+
for (let j = 0; j < dataColumnsCount; j += 1) {
|
|
201
|
+
// if multiple columns are grouped, we need to get the value from the parent to properly create dimension groups
|
|
202
|
+
let targetRow = rowsPerDepth[defaultDepth][i].model;
|
|
203
|
+
// 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
|
|
204
|
+
for (let d = defaultDepth; d > dataColumns[j].depth; d -= 1) {
|
|
205
|
+
const rowId = gridRowIdSelector(apiRef, targetRow);
|
|
206
|
+
targetRow = gridRowNodeSelector(apiRef, rowTree[rowId].parent);
|
|
207
|
+
}
|
|
208
|
+
const value = apiRef.current.getRowValue(targetRow, dataColumns[j]);
|
|
209
|
+
if (value !== null) {
|
|
210
|
+
data[dataColumns[j].dataFieldName].push(typeof value === 'object' && 'label' in value ? value.label : value);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
chartIds.forEach(chartId => {
|
|
215
|
+
setChartState(chartId, {
|
|
216
|
+
dimensions: visibleDimensions.current[chartId].map(dimension => ({
|
|
217
|
+
id: dimension.field,
|
|
218
|
+
label: getColumnName(dimension.field),
|
|
219
|
+
data: data[dimension.field] || []
|
|
220
|
+
})),
|
|
221
|
+
values: visibleValues.current[chartId].map(value => ({
|
|
222
|
+
id: value.field,
|
|
223
|
+
label: getValueDatasetLabel(value.field),
|
|
224
|
+
data: data[value.field] || []
|
|
225
|
+
}))
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}, [apiRef, activeChartId, orderedFields, getColumnName, getValueDatasetLabel, setChartState]);
|
|
229
|
+
const debouncedHandleRowDataUpdate = React.useMemo(() => debounce(handleRowDataUpdate, 0), [handleRowDataUpdate]);
|
|
230
|
+
const handleColumnDataUpdate = React.useCallback((chartIds, updatedChartStateLookup) => {
|
|
231
|
+
// if there are no charts, skip the data processing
|
|
232
|
+
if (chartIds.length === 0) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
|
|
236
|
+
const chartableColumns = gridChartableColumnsSelector(apiRef);
|
|
237
|
+
const selectedFields = chartIds.reduce((acc, chartId) => {
|
|
238
|
+
const values = gridChartsValuesSelector(apiRef, chartId);
|
|
239
|
+
const dimensions = gridChartsDimensionsSelector(apiRef, chartId);
|
|
240
|
+
return _extends({}, acc, {
|
|
241
|
+
[chartId]: {
|
|
242
|
+
values,
|
|
243
|
+
dimensions
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}, {});
|
|
247
|
+
const values = {};
|
|
248
|
+
const dimensions = {};
|
|
249
|
+
chartIds.forEach(chartId => {
|
|
250
|
+
dimensions[chartId] = [];
|
|
251
|
+
values[chartId] = [];
|
|
252
|
+
|
|
253
|
+
// loop through dimensions and values datasets either through their length or to the max limit
|
|
254
|
+
// if the current selection is greater than the max limit, the state will be updated
|
|
255
|
+
const chartState = updatedChartStateLookup?.[chartId] || chartStateLookup[chartId];
|
|
256
|
+
const dimensionsSize = chartState?.maxDimensions ? Math.min(chartState.maxDimensions, selectedFields[chartId].dimensions.length) : selectedFields[chartId].dimensions.length;
|
|
257
|
+
const valuesSize = chartState?.maxValues ? Math.min(chartState.maxValues, selectedFields[chartId].values.length) : selectedFields[chartId].values.length;
|
|
258
|
+
|
|
259
|
+
// sanitize selectedDimensions and selectedValues while maintaining their order
|
|
260
|
+
for (let i = 0; i < valuesSize; i += 1) {
|
|
261
|
+
if (chartableColumns[selectedFields[chartId].values[i].field] && !isBlockedForSection(chartableColumns[selectedFields[chartId].values[i].field], 'values', rowGroupingModel, pivotActive ? pivotModel : undefined)) {
|
|
262
|
+
if (!values[chartId]) {
|
|
263
|
+
values[chartId] = [];
|
|
264
|
+
}
|
|
265
|
+
values[chartId].push(selectedFields[chartId].values[i]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// dimensions cannot contain fields that are already in values
|
|
270
|
+
for (let i = 0; i < dimensionsSize; i += 1) {
|
|
271
|
+
const item = selectedFields[chartId].dimensions[i];
|
|
272
|
+
if (!selectedFields[chartId].values.some(valueItem => valueItem.field === item.field) && chartableColumns[item.field] && !isBlockedForSection(chartableColumns[item.field], 'dimensions', rowGroupingModel, pivotActive ? pivotModel : undefined)) {
|
|
273
|
+
if (!dimensions[chartId]) {
|
|
274
|
+
dimensions[chartId] = [];
|
|
275
|
+
}
|
|
276
|
+
dimensions[chartId].push(item);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// we can compare the lengths, because this function is called after the state was updated.
|
|
281
|
+
// different lengths will occur only if some items were removed during the checks above
|
|
282
|
+
if (dimensions[chartId] && selectedFields[chartId].dimensions.length !== dimensions[chartId].length) {
|
|
283
|
+
apiRef.current.updateChartDimensionsData(chartId, dimensions[chartId]);
|
|
284
|
+
}
|
|
285
|
+
if (values[chartId] && selectedFields[chartId].values.length !== values[chartId].length) {
|
|
286
|
+
apiRef.current.updateChartValuesData(chartId, values[chartId]);
|
|
287
|
+
}
|
|
288
|
+
visibleDimensions.current[chartId] = dimensions[chartId].filter(dimension => dimension.hidden !== true).map(dimension => chartableColumns[dimension.field]);
|
|
289
|
+
visibleValues.current[chartId] = values[chartId].filter(value => value.hidden !== true).map(value => chartableColumns[value.field]);
|
|
290
|
+
|
|
291
|
+
// we need to have both dimensions and values to be able to display the chart
|
|
292
|
+
if (visibleDimensions.current[chartId].length === 0 || visibleValues.current[chartId].length === 0) {
|
|
293
|
+
visibleDimensions.current[chartId] = [];
|
|
294
|
+
visibleValues.current[chartId] = [];
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
updateOtherModels();
|
|
298
|
+
handleRowDataUpdate(chartIds);
|
|
299
|
+
}, [apiRef, chartStateLookup, pivotActive, pivotModel, handleRowDataUpdate, updateOtherModels]);
|
|
300
|
+
const debouncedHandleColumnDataUpdate = React.useMemo(() => debounce(handleColumnDataUpdate, 0), [handleColumnDataUpdate]);
|
|
301
|
+
const setChartsPanelOpen = React.useCallback(callback => {
|
|
302
|
+
if (!isChartsIntegrationAvailable) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const panelOpen = gridChartsPanelOpenSelector(apiRef);
|
|
306
|
+
const newPanelOpen = typeof callback === 'function' ? callback(panelOpen) : callback;
|
|
307
|
+
if (panelOpen === newPanelOpen) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (newPanelOpen) {
|
|
311
|
+
apiRef.current.showSidebar(GridSidebarValue.Charts);
|
|
312
|
+
} else {
|
|
313
|
+
apiRef.current.hideSidebar();
|
|
314
|
+
}
|
|
315
|
+
}, [apiRef, isChartsIntegrationAvailable]);
|
|
316
|
+
const updateChartDimensionsData = React.useCallback((chartId, dimensions) => {
|
|
317
|
+
if (!isChartsIntegrationAvailable) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
apiRef.current.setState(state => {
|
|
321
|
+
const newDimensions = typeof dimensions === 'function' ? dimensions(state.chartsIntegration.charts[chartId].dimensions) : dimensions;
|
|
322
|
+
return _extends({}, state, {
|
|
323
|
+
chartsIntegration: _extends({}, state.chartsIntegration, {
|
|
324
|
+
charts: _extends({}, state.chartsIntegration.charts, {
|
|
325
|
+
[chartId]: _extends({}, state.chartsIntegration.charts[chartId], {
|
|
326
|
+
dimensions: newDimensions
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
})
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
debouncedHandleColumnDataUpdate(syncedChartIds);
|
|
333
|
+
}, [apiRef, isChartsIntegrationAvailable, syncedChartIds, debouncedHandleColumnDataUpdate]);
|
|
334
|
+
const updateChartValuesData = React.useCallback((chartId, values) => {
|
|
335
|
+
if (!isChartsIntegrationAvailable) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
apiRef.current.setState(state => {
|
|
339
|
+
const newValues = typeof values === 'function' ? values(state.chartsIntegration.charts[chartId].values) : values;
|
|
340
|
+
return _extends({}, state, {
|
|
341
|
+
chartsIntegration: _extends({}, state.chartsIntegration, {
|
|
342
|
+
charts: _extends({}, state.chartsIntegration.charts, {
|
|
343
|
+
[chartId]: _extends({}, state.chartsIntegration.charts[chartId], {
|
|
344
|
+
values: newValues
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
debouncedHandleColumnDataUpdate(syncedChartIds);
|
|
351
|
+
}, [apiRef, isChartsIntegrationAvailable, syncedChartIds, debouncedHandleColumnDataUpdate]);
|
|
352
|
+
const setActiveChartId = React.useCallback(chartId => {
|
|
353
|
+
if (!isChartsIntegrationAvailable) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
apiRef.current.setState(state => _extends({}, state, {
|
|
357
|
+
chartsIntegration: _extends({}, state.chartsIntegration, {
|
|
358
|
+
activeChartId: chartId
|
|
359
|
+
})
|
|
360
|
+
}));
|
|
361
|
+
}, [apiRef, isChartsIntegrationAvailable]);
|
|
362
|
+
const setChartType = React.useCallback((chartId, type) => {
|
|
363
|
+
if (!isChartsIntegrationAvailable || !chartStateLookup[chartId]) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const stateUpdate = {
|
|
367
|
+
type,
|
|
368
|
+
dimensionsLabel: schema[type]?.dimensionsLabel,
|
|
369
|
+
valuesLabel: schema[type]?.valuesLabel,
|
|
370
|
+
maxDimensions: schema[type]?.maxDimensions,
|
|
371
|
+
maxValues: schema[type]?.maxValues
|
|
372
|
+
};
|
|
373
|
+
const updatedChartStateLookup = _extends({}, chartStateLookup, {
|
|
374
|
+
[chartId]: _extends({}, chartStateLookup[chartId], stateUpdate)
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// make sure that the new dimensions and values limits are applied before changing the chart type
|
|
378
|
+
handleColumnDataUpdate([chartId], updatedChartStateLookup);
|
|
379
|
+
setChartState(chartId, stateUpdate);
|
|
380
|
+
}, [isChartsIntegrationAvailable, chartStateLookup, schema, setChartState, handleColumnDataUpdate]);
|
|
381
|
+
const setChartSynchronizationState = React.useCallback((chartId, synced) => {
|
|
382
|
+
if (!isChartsIntegrationAvailable || !chartStateLookup[chartId]) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const stateUpdate = {
|
|
386
|
+
synced
|
|
387
|
+
};
|
|
388
|
+
const updatedChartStateLookup = _extends({}, chartStateLookup, {
|
|
389
|
+
[chartId]: _extends({}, chartStateLookup[chartId], stateUpdate)
|
|
390
|
+
});
|
|
391
|
+
setChartState(chartId, stateUpdate);
|
|
392
|
+
apiRef.current.publishEvent('chartSynchronizationStateChange', {
|
|
393
|
+
chartId,
|
|
394
|
+
synced
|
|
395
|
+
});
|
|
396
|
+
if (synced) {
|
|
397
|
+
debouncedHandleColumnDataUpdate([chartId], updatedChartStateLookup);
|
|
398
|
+
}
|
|
399
|
+
}, [apiRef, isChartsIntegrationAvailable, chartStateLookup, setChartState, debouncedHandleColumnDataUpdate]);
|
|
400
|
+
|
|
401
|
+
// called when a column is dragged and dropped to a different section
|
|
402
|
+
const updateDataReference = React.useCallback((field, originSection, targetSection, targetField, placementRelativeToTargetField) => {
|
|
403
|
+
const columns = gridColumnLookupSelector(apiRef);
|
|
404
|
+
const dimensions = gridChartsDimensionsSelector(apiRef, activeChartId);
|
|
405
|
+
const values = gridChartsValuesSelector(apiRef, activeChartId);
|
|
406
|
+
const rowGroupingModel = gridRowGroupingSanitizedModelSelector(apiRef);
|
|
407
|
+
if (targetSection) {
|
|
408
|
+
if (isBlockedForSection(columns[field], targetSection, rowGroupingModel, pivotActive ? pivotModel : undefined)) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const currentTargetItems = targetSection === 'dimensions' ? dimensions : values;
|
|
412
|
+
const currentMaxItems = targetSection === 'dimensions' ? chartStateLookup[activeChartId]?.maxDimensions : chartStateLookup[activeChartId]?.maxValues;
|
|
413
|
+
if (currentMaxItems && currentTargetItems.length >= currentMaxItems) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
let hidden;
|
|
418
|
+
if (originSection) {
|
|
419
|
+
const method = originSection === 'dimensions' ? updateChartDimensionsData : updateChartValuesData;
|
|
420
|
+
const currentItems = originSection === 'dimensions' ? [...dimensions] : [...values];
|
|
421
|
+
const fieldIndex = currentItems.findIndex(item => item.field === field);
|
|
422
|
+
if (fieldIndex !== -1) {
|
|
423
|
+
hidden = currentItems[fieldIndex].hidden;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// if the target is another section, remove the field from the origin section
|
|
427
|
+
if (targetSection !== originSection) {
|
|
428
|
+
currentItems.splice(fieldIndex, 1);
|
|
429
|
+
method(activeChartId, currentItems);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
if (targetSection) {
|
|
433
|
+
const method = targetSection === 'dimensions' ? updateChartDimensionsData : updateChartValuesData;
|
|
434
|
+
const currentItems = targetSection === 'dimensions' ? dimensions : values;
|
|
435
|
+
const remainingItems = targetSection === originSection ? currentItems.filter(item => item.field !== field) : [...currentItems];
|
|
436
|
+
|
|
437
|
+
// with row grouping add the aggregation model to the newly added values dataset
|
|
438
|
+
if (rowGroupingModel.length > 0 && targetSection === 'values') {
|
|
439
|
+
const hasAggregation = Object.keys(aggregationModel).includes(field);
|
|
440
|
+
if (!hasAggregation) {
|
|
441
|
+
apiRef.current.setAggregationModel(_extends({}, aggregationModel, {
|
|
442
|
+
[field]: getAvailableAggregationFunctions({
|
|
443
|
+
aggregationFunctions: props.aggregationFunctions,
|
|
444
|
+
colDef: columns[field],
|
|
445
|
+
isDataSource: !!props.dataSource
|
|
446
|
+
})[0]
|
|
447
|
+
}));
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (targetField) {
|
|
451
|
+
const targetFieldIndex = remainingItems.findIndex(item => item.field === targetField);
|
|
452
|
+
const targetIndex = placementRelativeToTargetField === 'top' ? targetFieldIndex : targetFieldIndex + 1;
|
|
453
|
+
remainingItems.splice(targetIndex, 0, {
|
|
454
|
+
field,
|
|
455
|
+
hidden
|
|
456
|
+
});
|
|
457
|
+
method(activeChartId, remainingItems);
|
|
458
|
+
} else {
|
|
459
|
+
method(activeChartId, [...remainingItems, {
|
|
460
|
+
field,
|
|
461
|
+
hidden
|
|
462
|
+
}]);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}, [apiRef, props.aggregationFunctions, props.dataSource, activeChartId, chartStateLookup, updateChartDimensionsData, updateChartValuesData, aggregationModel, pivotActive, pivotModel]);
|
|
466
|
+
const addColumnMenuButton = React.useCallback(menuItems => {
|
|
467
|
+
if (isChartsIntegrationAvailable) {
|
|
468
|
+
return [...menuItems, 'columnMenuManagePanelItem'];
|
|
469
|
+
}
|
|
470
|
+
return menuItems;
|
|
471
|
+
}, [isChartsIntegrationAvailable]);
|
|
472
|
+
useGridRegisterPipeProcessor(apiRef, 'columnMenu', addColumnMenuButton);
|
|
473
|
+
const addChartsPanel = React.useCallback((initialValue, value) => {
|
|
474
|
+
if (props.slots.chartsPanel && isChartsIntegrationAvailable && value === GridSidebarValue.Charts) {
|
|
475
|
+
return /*#__PURE__*/_jsx(props.slots.chartsPanel, _extends({}, props.slotProps?.chartsPanel));
|
|
476
|
+
}
|
|
477
|
+
return initialValue;
|
|
478
|
+
}, [props, isChartsIntegrationAvailable]);
|
|
479
|
+
useGridRegisterPipeProcessor(apiRef, 'sidebar', addChartsPanel);
|
|
480
|
+
useGridApiMethod(apiRef, {
|
|
481
|
+
chartsIntegration: {
|
|
482
|
+
updateDataReference,
|
|
483
|
+
getColumnName
|
|
484
|
+
}
|
|
485
|
+
}, 'private');
|
|
486
|
+
useGridApiMethod(apiRef, props.experimentalFeatures?.charts ? {
|
|
487
|
+
setChartsPanelOpen,
|
|
488
|
+
setActiveChartId,
|
|
489
|
+
setChartType,
|
|
490
|
+
setChartSynchronizationState,
|
|
491
|
+
updateChartDimensionsData,
|
|
492
|
+
updateChartValuesData
|
|
493
|
+
} : {}, 'public');
|
|
494
|
+
useGridEvent(apiRef, 'columnsChange', runIf(isChartsIntegrationAvailable, () => debouncedHandleColumnDataUpdate(syncedChartIds)));
|
|
495
|
+
useGridEvent(apiRef, 'pivotModeChange', runIf(isChartsIntegrationAvailable, () => debouncedHandleColumnDataUpdate(syncedChartIds)));
|
|
496
|
+
useGridEvent(apiRef, 'filteredRowsSet', runIf(isChartsIntegrationAvailable, () => debouncedHandleRowDataUpdate(syncedChartIds)));
|
|
497
|
+
useGridEvent(apiRef, 'sortedRowsSet', runIf(isChartsIntegrationAvailable, () => debouncedHandleRowDataUpdate(syncedChartIds)));
|
|
498
|
+
React.useEffect(() => {
|
|
499
|
+
if (!activeChartId && availableChartIds.length > 0) {
|
|
500
|
+
setActiveChartId(availableChartIds[0]);
|
|
501
|
+
}
|
|
502
|
+
}, [availableChartIds, activeChartId, setActiveChartId]);
|
|
503
|
+
const isInitialized = React.useRef(false);
|
|
504
|
+
React.useEffect(() => {
|
|
505
|
+
if (isInitialized.current) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (availableChartIds.length === 0) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
isInitialized.current = true;
|
|
512
|
+
availableChartIds.forEach(chartId => {
|
|
513
|
+
const chartType = props.initialState?.chartsIntegration?.charts?.[chartId]?.chartType || '';
|
|
514
|
+
setChartState(chartId, {
|
|
515
|
+
type: chartType,
|
|
516
|
+
maxDimensions: schema[chartType]?.maxDimensions,
|
|
517
|
+
maxValues: schema[chartType]?.maxValues,
|
|
518
|
+
dimensionsLabel: schema[chartType]?.dimensionsLabel,
|
|
519
|
+
valuesLabel: schema[chartType]?.valuesLabel,
|
|
520
|
+
configuration: props.initialState?.chartsIntegration?.charts?.[chartId]?.configuration || {}
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
debouncedHandleColumnDataUpdate(syncedChartIds);
|
|
524
|
+
}, [schema, availableChartIds, syncedChartIds, props.initialState?.chartsIntegration?.charts, setChartState, debouncedHandleColumnDataUpdate]);
|
|
525
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { GridColDef } from '@mui/x-data-grid-pro';
|
|
2
|
+
import { GridRowGroupingModel } from "../rowGrouping/gridRowGroupingInterfaces.js";
|
|
3
|
+
import { GridPivotModel } from "../pivoting/gridPivotingInterfaces.js";
|
|
4
|
+
export declare const getBlockedSections: (column: GridColDef, rowGroupingModel: GridRowGroupingModel, pivotModel: GridPivotModel | undefined) => string[];
|
|
5
|
+
export declare const isBlockedForSection: (column: GridColDef, section: string, rowGroupingModel: GridRowGroupingModel, pivotModel: GridPivotModel | undefined) => boolean;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { COLUMN_GROUP_ID_SEPARATOR } from "../../../constants/columnGroups.js";
|
|
2
|
+
export const getBlockedSections = (column, rowGroupingModel, pivotModel) => {
|
|
3
|
+
// with pivoting, columns that are pivot values can only be added to the chart values
|
|
4
|
+
// grid columns that are pivot rows can only be added to the chart dimensions
|
|
5
|
+
// the rest of the columns can be added anywhere
|
|
6
|
+
// pivoting columns are already filtered out by the chartable columns selector
|
|
7
|
+
if (pivotModel) {
|
|
8
|
+
const sections = [];
|
|
9
|
+
const rows = pivotModel.rows.filter(item => item.hidden !== true).map(item => item.field);
|
|
10
|
+
const values = pivotModel.values.filter(item => item.hidden !== true).map(item => item.field);
|
|
11
|
+
|
|
12
|
+
// field names in the values contain the group path. We are comparing the last part of it (the actual field name used for the value)
|
|
13
|
+
const unwrappedFieldName = column.field.split(COLUMN_GROUP_ID_SEPARATOR).pop();
|
|
14
|
+
if (values.includes(unwrappedFieldName)) {
|
|
15
|
+
sections.push('dimensions');
|
|
16
|
+
}
|
|
17
|
+
if (rows.includes(column.field)) {
|
|
18
|
+
sections.push('values');
|
|
19
|
+
}
|
|
20
|
+
return sections;
|
|
21
|
+
}
|
|
22
|
+
// field that is already used for grouping cannot be added to the values
|
|
23
|
+
if (rowGroupingModel.length > 0) {
|
|
24
|
+
return rowGroupingModel.includes(column.field) ? ['values'] : [];
|
|
25
|
+
}
|
|
26
|
+
// without pivoting and row grouping the only constraint is that non-number columns cannot be added to the values
|
|
27
|
+
if (column.type !== 'number') {
|
|
28
|
+
return ['values'];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
};
|
|
32
|
+
export const isBlockedForSection = (column, section, rowGroupingModel, pivotModel) => getBlockedSections(column, rowGroupingModel, pivotModel).includes(section);
|
|
@@ -269,7 +269,7 @@ export const useGridPivoting = (apiRef, props, originalColumnsProp, originalRows
|
|
|
269
269
|
}, [apiRef, isPivotingAvailable]);
|
|
270
270
|
const addColumnMenuButton = React.useCallback(menuItems => {
|
|
271
271
|
if (isPivotingAvailable) {
|
|
272
|
-
return [...menuItems, '
|
|
272
|
+
return [...menuItems, 'columnMenuManagePanelItem'];
|
|
273
273
|
}
|
|
274
274
|
return menuItems;
|
|
275
275
|
}, [isPivotingAvailable]);
|