@mui/x-data-grid-pro 7.7.0 → 7.8.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.
Files changed (111) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/DataGridPro/DataGridPro.js +13 -1
  3. package/DataGridPro/useDataGridProComponent.js +6 -1
  4. package/DataGridPro/useDataGridProProps.js +10 -3
  5. package/components/GridDataSourceTreeDataGroupingCell.d.ts +12 -0
  6. package/components/GridDataSourceTreeDataGroupingCell.js +120 -0
  7. package/components/GridTreeDataGroupingCell.js +1 -4
  8. package/esm/DataGridPro/DataGridPro.js +13 -1
  9. package/esm/DataGridPro/useDataGridProComponent.js +6 -1
  10. package/esm/DataGridPro/useDataGridProProps.js +9 -3
  11. package/esm/components/GridDataSourceTreeDataGroupingCell.js +111 -0
  12. package/esm/components/GridTreeDataGroupingCell.js +1 -4
  13. package/esm/hooks/features/dataSource/cache.js +36 -0
  14. package/esm/hooks/features/dataSource/gridDataSourceSelector.js +24 -0
  15. package/esm/hooks/features/dataSource/useGridDataSource.js +218 -0
  16. package/esm/hooks/features/dataSource/utils.js +87 -0
  17. package/esm/hooks/features/index.js +3 -1
  18. package/esm/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.js +148 -0
  19. package/esm/hooks/features/serverSideTreeData/utils.js +18 -0
  20. package/esm/hooks/features/treeData/useGridTreeData.js +6 -2
  21. package/esm/hooks/features/treeData/useGridTreeDataPreProcessors.js +6 -3
  22. package/esm/internals/index.js +2 -0
  23. package/esm/internals/propValidation.js +1 -1
  24. package/esm/models/index.js +2 -1
  25. package/esm/utils/releaseInfo.js +1 -1
  26. package/esm/utils/tree/createRowTree.js +6 -2
  27. package/esm/utils/tree/insertDataRowInTree.js +34 -10
  28. package/esm/utils/tree/updateRowTree.js +13 -5
  29. package/esm/utils/tree/utils.js +5 -1
  30. package/hooks/features/columnHeaders/useGridColumnHeaders.d.ts +1 -1
  31. package/hooks/features/columnPinning/useGridColumnPinning.d.ts +1 -1
  32. package/hooks/features/columnReorder/useGridColumnReorder.d.ts +1 -1
  33. package/hooks/features/dataSource/cache.d.ts +18 -0
  34. package/hooks/features/dataSource/cache.js +43 -0
  35. package/hooks/features/dataSource/gridDataSourceSelector.d.ts +14 -0
  36. package/hooks/features/dataSource/gridDataSourceSelector.js +32 -0
  37. package/hooks/features/dataSource/interfaces.d.ts +50 -0
  38. package/hooks/features/dataSource/useGridDataSource.d.ts +6 -0
  39. package/hooks/features/dataSource/useGridDataSource.js +229 -0
  40. package/hooks/features/dataSource/utils.d.ts +29 -0
  41. package/hooks/features/dataSource/utils.js +95 -0
  42. package/hooks/features/detailPanel/gridDetailPanelSelector.d.ts +0 -1
  43. package/hooks/features/detailPanel/useGridDetailPanel.d.ts +1 -1
  44. package/hooks/features/index.d.ts +2 -0
  45. package/hooks/features/index.js +22 -0
  46. package/hooks/features/infiniteLoader/useGridInfiniteLoader.d.ts +1 -1
  47. package/hooks/features/lazyLoader/useGridLazyLoader.d.ts +1 -1
  48. package/hooks/features/lazyLoader/useGridLazyLoaderPreProcessors.d.ts +1 -1
  49. package/hooks/features/rowPinning/useGridRowPinning.d.ts +1 -1
  50. package/hooks/features/rowPinning/useGridRowPinningPreProcessors.d.ts +2 -2
  51. package/hooks/features/rowReorder/useGridRowReorder.d.ts +1 -1
  52. package/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.d.ts +4 -0
  53. package/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.js +158 -0
  54. package/hooks/features/serverSideTreeData/utils.d.ts +6 -0
  55. package/hooks/features/serverSideTreeData/utils.js +25 -0
  56. package/hooks/features/treeData/gridTreeDataUtils.d.ts +1 -2
  57. package/hooks/features/treeData/useGridTreeData.d.ts +2 -1
  58. package/hooks/features/treeData/useGridTreeData.js +6 -2
  59. package/hooks/features/treeData/useGridTreeDataPreProcessors.d.ts +1 -1
  60. package/hooks/features/treeData/useGridTreeDataPreProcessors.js +6 -3
  61. package/hooks/utils/useGridApiContext.d.ts +0 -1
  62. package/hooks/utils/useGridApiRef.d.ts +0 -1
  63. package/hooks/utils/useGridPrivateApiContext.d.ts +0 -1
  64. package/index.js +1 -1
  65. package/internals/index.d.ts +2 -0
  66. package/internals/index.js +23 -0
  67. package/internals/propValidation.js +1 -1
  68. package/material/index.d.ts +0 -1
  69. package/models/dataGridProProps.d.ts +17 -11
  70. package/models/gridApiPro.d.ts +3 -3
  71. package/models/gridProSlotsComponent.d.ts +0 -1
  72. package/models/gridStatePro.d.ts +2 -0
  73. package/models/index.d.ts +1 -0
  74. package/modern/DataGridPro/DataGridPro.js +13 -1
  75. package/modern/DataGridPro/useDataGridProComponent.js +6 -1
  76. package/modern/DataGridPro/useDataGridProProps.js +9 -3
  77. package/modern/components/GridDataSourceTreeDataGroupingCell.js +111 -0
  78. package/modern/components/GridTreeDataGroupingCell.js +1 -4
  79. package/modern/hooks/features/dataSource/cache.js +36 -0
  80. package/modern/hooks/features/dataSource/gridDataSourceSelector.js +24 -0
  81. package/modern/hooks/features/dataSource/useGridDataSource.js +218 -0
  82. package/modern/hooks/features/dataSource/utils.js +87 -0
  83. package/modern/hooks/features/index.js +3 -1
  84. package/modern/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.js +148 -0
  85. package/modern/hooks/features/serverSideTreeData/utils.js +18 -0
  86. package/modern/hooks/features/treeData/useGridTreeData.js +6 -2
  87. package/modern/hooks/features/treeData/useGridTreeDataPreProcessors.js +6 -3
  88. package/modern/index.js +1 -1
  89. package/modern/internals/index.js +2 -0
  90. package/modern/internals/propValidation.js +1 -1
  91. package/modern/models/index.js +2 -1
  92. package/modern/utils/releaseInfo.js +1 -1
  93. package/modern/utils/tree/createRowTree.js +6 -2
  94. package/modern/utils/tree/insertDataRowInTree.js +34 -10
  95. package/modern/utils/tree/updateRowTree.js +13 -5
  96. package/modern/utils/tree/utils.js +5 -1
  97. package/package.json +5 -5
  98. package/typeOverloads/modules.d.ts +0 -1
  99. package/utils/releaseInfo.js +1 -1
  100. package/utils/tree/createRowTree.js +6 -2
  101. package/utils/tree/insertDataRowInTree.d.ts +3 -1
  102. package/utils/tree/insertDataRowInTree.js +33 -9
  103. package/utils/tree/models.d.ts +1 -0
  104. package/utils/tree/updateRowTree.d.ts +1 -0
  105. package/utils/tree/updateRowTree.js +13 -5
  106. package/utils/tree/utils.d.ts +5 -4
  107. package/utils/tree/utils.js +7 -2
  108. package/models/dataSource.d.ts +0 -64
  109. /package/esm/{models/dataSource.js → hooks/features/dataSource/interfaces.js} +0 -0
  110. /package/{models/dataSource.js → hooks/features/dataSource/interfaces.js} +0 -0
  111. /package/modern/{models/dataSource.js → hooks/features/dataSource/interfaces.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { GridEventListener, GridCallbackDetails, GridRowParams, GridRowId, GridValidRowModel, GridGroupNode, GridFeatureMode } from '@mui/x-data-grid';
3
- import { GridExperimentalFeatures, DataGridPropsWithoutDefaultValue, DataGridPropsWithDefaultValues, DataGridPropsWithComplexDefaultValueAfterProcessing, DataGridPropsWithComplexDefaultValueBeforeProcessing, GridPinnedColumnFields, DataGridProSharedPropsWithDefaultValue, DataGridProSharedPropsWithoutDefaultValue } from '@mui/x-data-grid/internals';
3
+ import type { GridExperimentalFeatures, DataGridPropsWithoutDefaultValue, DataGridPropsWithDefaultValues, DataGridPropsWithComplexDefaultValueAfterProcessing, DataGridPropsWithComplexDefaultValueBeforeProcessing, GridPinnedColumnFields, DataGridProSharedPropsWithDefaultValue, DataGridProSharedPropsWithoutDefaultValue, GridDataSourceCache, GridGetRowsParams } from '@mui/x-data-grid/internals';
4
4
  import type { GridPinnedRowsProp } from '../hooks/features/rowPinning';
5
5
  import { GridApiPro } from './gridApiPro';
6
6
  import { GridGroupingColDefOverride, GridGroupingColDefOverrideParams } from './gridGroupingColDefOverride';
@@ -99,7 +99,22 @@ export interface DataGridProPropsWithDefaultValue<R extends GridValidRowModel =
99
99
  */
100
100
  keepColumnPositionIfDraggedOutside: boolean;
101
101
  }
102
- export interface DataGridProPropsWithoutDefaultValue<R extends GridValidRowModel = any> extends Omit<DataGridPropsWithoutDefaultValue<R>, 'initialState' | 'componentsProps' | 'slotProps'>, DataGridProSharedPropsWithoutDefaultValue {
102
+ interface DataGridProDataSourceProps {
103
+ unstable_dataSourceCache?: GridDataSourceCache | null;
104
+ unstable_onDataSourceError?: (error: Error, params: GridGetRowsParams) => void;
105
+ }
106
+ interface DataGridProRegularProps<R extends GridValidRowModel> {
107
+ /**
108
+ * Determines the path of a row in the tree data.
109
+ * For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"].
110
+ * Note that all paths must contain at least one element.
111
+ * @template R
112
+ * @param {R} row The row from which we want the path.
113
+ * @returns {string[]} The path to the row.
114
+ */
115
+ getTreeDataPath?: (row: R) => string[];
116
+ }
117
+ export interface DataGridProPropsWithoutDefaultValue<R extends GridValidRowModel = any> extends Omit<DataGridPropsWithoutDefaultValue<R>, 'initialState' | 'componentsProps' | 'slotProps'>, DataGridProRegularProps<R>, DataGridProDataSourceProps, DataGridProSharedPropsWithoutDefaultValue {
103
118
  /**
104
119
  * The ref object that allows grid manipulation. Can be instantiated with `useGridApiRef()`.
105
120
  */
@@ -115,15 +130,6 @@ export interface DataGridProPropsWithoutDefaultValue<R extends GridValidRowModel
115
130
  * For each feature, if the flag is not explicitly set to `true`, the feature will be fully disabled and any property / method call will not have any effect.
116
131
  */
117
132
  experimentalFeatures?: Partial<GridExperimentalProFeatures>;
118
- /**
119
- * Determines the path of a row in the tree data.
120
- * For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"].
121
- * Note that all paths must contain at least one element.
122
- * @template R
123
- * @param {R} row The row from which we want the path.
124
- * @returns {string[]} The path to the row.
125
- */
126
- getTreeDataPath?: (row: R) => string[];
127
133
  /**
128
134
  * Callback fired when scrolling to the bottom of the grid viewport.
129
135
  * @param {GridRowScrollEndParams} params With all properties from [[GridRowScrollEndParams]].
@@ -1,12 +1,12 @@
1
1
  import { GridApiCommon, GridColumnReorderApi, GridRowMultiSelectionApi, GridRowProApi } from '@mui/x-data-grid';
2
2
  import { GridPrivateOnlyApiCommon, GridInfiniteLoaderPrivateApi } from '@mui/x-data-grid/internals';
3
3
  import { GridInitialStatePro, GridStatePro } from './gridStatePro';
4
- import type { GridColumnPinningApi, GridDetailPanelApi, GridRowPinningApi, GridDetailPanelPrivateApi } from '../hooks';
4
+ import type { GridColumnPinningApi, GridDetailPanelApi, GridRowPinningApi, GridDetailPanelPrivateApi, GridDataSourceApi, GridDataSourcePrivateApi } from '../hooks';
5
5
  import type { DataGridProProcessedProps } from './dataGridProProps';
6
6
  /**
7
7
  * The api of `DataGridPro`.
8
8
  */
9
- export interface GridApiPro extends GridApiCommon<GridStatePro, GridInitialStatePro>, GridRowProApi, GridColumnPinningApi, GridDetailPanelApi, GridRowPinningApi, GridRowMultiSelectionApi, GridColumnReorderApi {
9
+ export interface GridApiPro extends GridApiCommon<GridStatePro, GridInitialStatePro>, GridRowProApi, GridColumnPinningApi, GridDetailPanelApi, GridRowPinningApi, GridDataSourceApi, GridRowMultiSelectionApi, GridColumnReorderApi {
10
10
  }
11
- export interface GridPrivateApiPro extends GridApiPro, GridPrivateOnlyApiCommon<GridApiPro, GridPrivateApiPro, DataGridProProcessedProps>, GridDetailPanelPrivateApi, GridInfiniteLoaderPrivateApi {
11
+ export interface GridPrivateApiPro extends GridApiPro, GridPrivateOnlyApiCommon<GridApiPro, GridPrivateApiPro, DataGridProProcessedProps>, GridDetailPanelPrivateApi, GridInfiniteLoaderPrivateApi, GridDataSourcePrivateApi {
12
12
  }
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { GridSlotsComponent } from '@mui/x-data-grid';
3
2
  import { GridProIconSlotsComponent } from './gridProIconSlotsComponent';
4
3
  /**
@@ -1,5 +1,6 @@
1
1
  import { GridInitialState as GridInitialStateCommunity, GridState as GridStateCommunity, GridColumnPinningState, GridPinnedColumnFields } from '@mui/x-data-grid';
2
2
  import type { GridDetailPanelState, GridDetailPanelInitialState, GridColumnReorderState } from '../hooks';
3
+ import type { GridDataSourceState } from '../hooks/features/dataSource/interfaces';
3
4
  /**
4
5
  * The state of `DataGridPro`.
5
6
  */
@@ -7,6 +8,7 @@ export interface GridStatePro extends GridStateCommunity {
7
8
  columnReorder: GridColumnReorderState;
8
9
  pinnedColumns: GridColumnPinningState;
9
10
  detailPanel: GridDetailPanelState;
11
+ dataSource: GridDataSourceState;
10
12
  }
11
13
  /**
12
14
  * The initial state of `DataGridPro`.
package/models/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export type { GridGetRowsParams, GridGetRowsResponse, GridDataSource, GridDataSourceCache, } from '@mui/x-data-grid/internals';
1
2
  export * from './gridApiPro';
2
3
  export * from './gridGroupingColDefOverride';
3
4
  export * from './gridRowScrollEndParams';
@@ -898,5 +898,17 @@ DataGridProRaw.propTypes = {
898
898
  * If `true`, the rows will be gathered in a tree structure according to the `getTreeDataPath` prop.
899
899
  * @default false
900
900
  */
901
- treeData: PropTypes.bool
901
+ treeData: PropTypes.bool,
902
+ unstable_dataSource: PropTypes.shape({
903
+ getChildrenCount: PropTypes.func,
904
+ getGroupKey: PropTypes.func,
905
+ getRows: PropTypes.func.isRequired,
906
+ updateRow: PropTypes.func
907
+ }),
908
+ unstable_dataSourceCache: PropTypes.shape({
909
+ clear: PropTypes.func.isRequired,
910
+ get: PropTypes.func.isRequired,
911
+ set: PropTypes.func.isRequired
912
+ }),
913
+ unstable_onDataSourceError: PropTypes.func
902
914
  };
@@ -4,6 +4,7 @@ import { useGridInfiniteLoader } from '../hooks/features/infiniteLoader/useGridI
4
4
  import { useGridColumnReorder, columnReorderStateInitializer } from '../hooks/features/columnReorder/useGridColumnReorder';
5
5
  import { useGridTreeData } from '../hooks/features/treeData/useGridTreeData';
6
6
  import { useGridTreeDataPreProcessors } from '../hooks/features/treeData/useGridTreeDataPreProcessors';
7
+ import { useGridDataSourceTreeDataPreProcessors } from '../hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors';
7
8
  import { useGridColumnPinning, columnPinningStateInitializer } from '../hooks/features/columnPinning/useGridColumnPinning';
8
9
  import { useGridColumnPinningPreProcessors } from '../hooks/features/columnPinning/useGridColumnPinningPreProcessors';
9
10
  import { useGridDetailPanel, detailPanelStateInitializer } from '../hooks/features/detailPanel/useGridDetailPanel';
@@ -14,6 +15,7 @@ import { useGridLazyLoader } from '../hooks/features/lazyLoader/useGridLazyLoade
14
15
  import { useGridLazyLoaderPreProcessors } from '../hooks/features/lazyLoader/useGridLazyLoaderPreProcessors';
15
16
  import { useGridRowPinning, rowPinningStateInitializer } from '../hooks/features/rowPinning/useGridRowPinning';
16
17
  import { useGridRowPinningPreProcessors } from '../hooks/features/rowPinning/useGridRowPinningPreProcessors';
18
+ import { useGridDataSource, dataSourceStateInitializer } from '../hooks/features/dataSource/useGridDataSource';
17
19
  export const useDataGridProComponent = (inputApiRef, props) => {
18
20
  const apiRef = useGridInitialization(inputApiRef, props);
19
21
 
@@ -23,6 +25,7 @@ export const useDataGridProComponent = (inputApiRef, props) => {
23
25
  useGridRowSelectionPreProcessors(apiRef, props);
24
26
  useGridRowReorderPreProcessors(apiRef, props);
25
27
  useGridTreeDataPreProcessors(apiRef, props);
28
+ useGridDataSourceTreeDataPreProcessors(apiRef, props);
26
29
  useGridLazyLoaderPreProcessors(apiRef, props);
27
30
  useGridRowPinningPreProcessors(apiRef);
28
31
  useGridDetailPanelPreProcessors(apiRef, props);
@@ -55,8 +58,9 @@ export const useDataGridProComponent = (inputApiRef, props) => {
55
58
  useGridInitializeState(columnMenuStateInitializer, apiRef, props);
56
59
  useGridInitializeState(columnGroupsStateInitializer, apiRef, props);
57
60
  useGridInitializeState(virtualizationStateInitializer, apiRef, props);
61
+ useGridInitializeState(dataSourceStateInitializer, apiRef, props);
58
62
  useGridHeaderFiltering(apiRef, props);
59
- useGridTreeData(apiRef);
63
+ useGridTreeData(apiRef, props);
60
64
  useGridKeyboardNavigation(apiRef, props);
61
65
  useGridRowSelection(apiRef, props);
62
66
  useGridColumnPinning(apiRef, props);
@@ -89,5 +93,6 @@ export const useDataGridProComponent = (inputApiRef, props) => {
89
93
  useGridEvents(apiRef, props);
90
94
  useGridStatePersistence(apiRef);
91
95
  useGridVirtualization(apiRef, props);
96
+ useGridDataSource(apiRef, props);
92
97
  return apiRef;
93
98
  };
@@ -4,6 +4,13 @@ import { useThemeProps } from '@mui/material/styles';
4
4
  import { GRID_DEFAULT_LOCALE_TEXT, DATA_GRID_PROPS_DEFAULT_VALUES } from '@mui/x-data-grid';
5
5
  import { computeSlots, useProps } from '@mui/x-data-grid/internals';
6
6
  import { DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS } from '../constants/dataGridProDefaultSlotsComponents';
7
+ const getDataGridProForcedProps = themedProps => _extends({
8
+ signature: 'DataGridPro'
9
+ }, themedProps.unstable_dataSource ? {
10
+ filterMode: 'server',
11
+ sortingMode: 'server',
12
+ paginationMode: 'server'
13
+ } : {});
7
14
 
8
15
  /**
9
16
  * The default values of `DataGridProPropsWithDefaultValue` to inject in the props of DataGridPro.
@@ -38,7 +45,6 @@ export const useDataGridProProps = inProps => {
38
45
  }), [themedProps.slots]);
39
46
  return React.useMemo(() => _extends({}, DATA_GRID_PRO_PROPS_DEFAULT_VALUES, themedProps, {
40
47
  localeText,
41
- slots,
42
- signature: 'DataGridPro'
43
- }), [themedProps, localeText, slots]);
48
+ slots
49
+ }, getDataGridProForcedProps(themedProps)), [themedProps, localeText, slots]);
44
50
  };
@@ -0,0 +1,111 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import * as React from 'react';
3
+ import { unstable_composeClasses as composeClasses } from '@mui/utils';
4
+ import Box from '@mui/material/Box';
5
+ import Badge from '@mui/material/Badge';
6
+ import { getDataGridUtilityClass, useGridSelector } from '@mui/x-data-grid';
7
+ import CircularProgress from '@mui/material/CircularProgress';
8
+ import { useGridRootProps } from '../hooks/utils/useGridRootProps';
9
+ import { useGridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext';
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ const useUtilityClasses = ownerState => {
12
+ const {
13
+ classes
14
+ } = ownerState;
15
+ const slots = {
16
+ root: ['treeDataGroupingCell'],
17
+ toggle: ['treeDataGroupingCellToggle'],
18
+ loadingContainer: ['treeDataGroupingCellLoadingContainer']
19
+ };
20
+ return composeClasses(slots, getDataGridUtilityClass, classes);
21
+ };
22
+ function GridTreeDataGroupingCellIcon(props) {
23
+ const apiRef = useGridPrivateApiContext();
24
+ const rootProps = useGridRootProps();
25
+ const classes = useUtilityClasses(rootProps);
26
+ const {
27
+ rowNode,
28
+ id,
29
+ field,
30
+ descendantCount
31
+ } = props;
32
+ const loadingSelector = state => state.dataSource.loading[id] ?? false;
33
+ const errorSelector = state => state.dataSource.errors[id];
34
+ const isDataLoading = useGridSelector(apiRef, loadingSelector);
35
+ const error = useGridSelector(apiRef, errorSelector);
36
+ const handleClick = event => {
37
+ if (!rowNode.childrenExpanded) {
38
+ // always fetch/get from cache the children when the node is expanded
39
+ apiRef.current.unstable_dataSource.fetchRows(id);
40
+ } else {
41
+ apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded);
42
+ }
43
+ apiRef.current.setCellFocus(id, field);
44
+ event.stopPropagation(); // TODO remove event.stopPropagation
45
+ };
46
+ const Icon = rowNode.childrenExpanded ? rootProps.slots.treeDataCollapseIcon : rootProps.slots.treeDataExpandIcon;
47
+ if (isDataLoading) {
48
+ return /*#__PURE__*/_jsx("div", {
49
+ className: classes.loadingContainer,
50
+ children: /*#__PURE__*/_jsx(CircularProgress, {
51
+ size: "1rem",
52
+ color: "inherit"
53
+ })
54
+ });
55
+ }
56
+ return descendantCount > 0 ? /*#__PURE__*/_jsx(rootProps.slots.baseIconButton, _extends({
57
+ size: "small",
58
+ onClick: handleClick,
59
+ tabIndex: -1,
60
+ "aria-label": rowNode.childrenExpanded ? apiRef.current.getLocaleText('treeDataCollapse') : apiRef.current.getLocaleText('treeDataExpand')
61
+ }, rootProps?.slotProps?.baseIconButton, {
62
+ children: /*#__PURE__*/_jsx(rootProps.slots.baseTooltip, {
63
+ title: error?.message ?? null,
64
+ children: /*#__PURE__*/_jsx(Badge, {
65
+ variant: "dot",
66
+ color: "error",
67
+ invisible: !error,
68
+ children: /*#__PURE__*/_jsx(Icon, {
69
+ fontSize: "inherit"
70
+ })
71
+ })
72
+ })
73
+ })) : null;
74
+ }
75
+ export function GridDataSourceTreeDataGroupingCell(props) {
76
+ const {
77
+ id,
78
+ field,
79
+ formattedValue,
80
+ rowNode,
81
+ hideDescendantCount,
82
+ offsetMultiplier = 2
83
+ } = props;
84
+ const rootProps = useGridRootProps();
85
+ const apiRef = useGridPrivateApiContext();
86
+ const rowSelector = state => state.rows.dataRowIdToModelLookup[id];
87
+ const row = useGridSelector(apiRef, rowSelector);
88
+ const classes = useUtilityClasses(rootProps);
89
+ let descendantCount = 0;
90
+ if (row) {
91
+ descendantCount = Math.max(rootProps.unstable_dataSource?.getChildrenCount?.(row) ?? 0, 0);
92
+ }
93
+ return /*#__PURE__*/_jsxs(Box, {
94
+ className: classes.root,
95
+ sx: {
96
+ ml: rowNode.depth * offsetMultiplier
97
+ },
98
+ children: [/*#__PURE__*/_jsx("div", {
99
+ className: classes.toggle,
100
+ children: /*#__PURE__*/_jsx(GridTreeDataGroupingCellIcon, {
101
+ id: id,
102
+ field: field,
103
+ rowNode: rowNode,
104
+ row: row,
105
+ descendantCount: descendantCount
106
+ })
107
+ }), /*#__PURE__*/_jsxs("span", {
108
+ children: [formattedValue === undefined ? rowNode.groupingKey : formattedValue, !hideDescendantCount && descendantCount > 0 ? ` (${descendantCount})` : '']
109
+ })]
110
+ });
111
+ }
@@ -28,10 +28,7 @@ function GridTreeDataGroupingCell(props) {
28
28
  } = props;
29
29
  const rootProps = useGridRootProps();
30
30
  const apiRef = useGridApiContext();
31
- const ownerState = {
32
- classes: rootProps.classes
33
- };
34
- const classes = useUtilityClasses(ownerState);
31
+ const classes = useUtilityClasses(rootProps);
35
32
  const filteredDescendantCountLookup = useGridSelector(apiRef, gridFilteredDescendantCountLookupSelector);
36
33
  const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0;
37
34
  const Icon = rowNode.childrenExpanded ? rootProps.slots.treeDataCollapseIcon : rootProps.slots.treeDataExpandIcon;
@@ -0,0 +1,36 @@
1
+ function getKey(params) {
2
+ return JSON.stringify([params.paginationModel, params.filterModel, params.sortModel, params.groupKeys]);
3
+ }
4
+ export class GridDataSourceCacheDefault {
5
+ constructor({
6
+ ttl = 300000
7
+ }) {
8
+ this.cache = void 0;
9
+ this.ttl = void 0;
10
+ this.cache = {};
11
+ this.ttl = ttl;
12
+ }
13
+ set(key, value) {
14
+ const keyString = getKey(key);
15
+ const expiry = Date.now() + this.ttl;
16
+ this.cache[keyString] = {
17
+ value,
18
+ expiry
19
+ };
20
+ }
21
+ get(key) {
22
+ const keyString = getKey(key);
23
+ const entry = this.cache[keyString];
24
+ if (!entry) {
25
+ return undefined;
26
+ }
27
+ if (Date.now() > entry.expiry) {
28
+ delete this.cache[keyString];
29
+ return undefined;
30
+ }
31
+ return entry.value;
32
+ }
33
+ clear() {
34
+ this.cache = {};
35
+ }
36
+ }
@@ -0,0 +1,24 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import { gridFilterModelSelector, gridSortModelSelector, gridPaginationModelSelector } from '@mui/x-data-grid';
3
+ import { createSelector } from '@mui/x-data-grid/internals';
4
+ const computeStartEnd = paginationModel => {
5
+ const start = paginationModel.page * paginationModel.pageSize;
6
+ const end = start + paginationModel.pageSize - 1;
7
+ return {
8
+ start,
9
+ end
10
+ };
11
+ };
12
+ export const gridGetRowsParamsSelector = createSelector(gridFilterModelSelector, gridSortModelSelector, gridPaginationModelSelector, (filterModel, sortModel, paginationModel) => {
13
+ return _extends({
14
+ groupKeys: [],
15
+ // TODO: Implement with `rowGrouping`
16
+ groupFields: [],
17
+ paginationModel,
18
+ sortModel,
19
+ filterModel
20
+ }, computeStartEnd(paginationModel));
21
+ });
22
+ export const gridDataSourceStateSelector = state => state.dataSource;
23
+ export const gridDataSourceLoadingSelector = createSelector(gridDataSourceStateSelector, dataSource => dataSource.loading);
24
+ export const gridDataSourceErrorsSelector = createSelector(gridDataSourceStateSelector, dataSource => dataSource.errors);
@@ -0,0 +1,218 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ import * as React from 'react';
3
+ import useLazyRef from '@mui/utils/useLazyRef';
4
+ import { useGridApiEventHandler, gridRowsLoadingSelector, useGridApiMethod, useGridSelector } from '@mui/x-data-grid';
5
+ import { gridRowGroupsToFetchSelector } from '@mui/x-data-grid/internals';
6
+ import { gridGetRowsParamsSelector, gridDataSourceErrorsSelector } from './gridDataSourceSelector';
7
+ import { runIfServerMode, NestedDataManager, RequestStatus } from './utils';
8
+ import { GridDataSourceCacheDefault } from './cache';
9
+ const INITIAL_STATE = {
10
+ loading: {},
11
+ errors: {}
12
+ };
13
+ const noopCache = {
14
+ clear: () => {},
15
+ get: () => undefined,
16
+ set: () => {}
17
+ };
18
+ function getCache(cacheProp) {
19
+ if (cacheProp === null) {
20
+ return noopCache;
21
+ }
22
+ return cacheProp ?? new GridDataSourceCacheDefault({});
23
+ }
24
+ export const dataSourceStateInitializer = state => {
25
+ return _extends({}, state, {
26
+ dataSource: INITIAL_STATE
27
+ });
28
+ };
29
+ export const useGridDataSource = (apiRef, props) => {
30
+ const nestedDataManager = useLazyRef(() => new NestedDataManager(apiRef)).current;
31
+ const groupsToAutoFetch = useGridSelector(apiRef, gridRowGroupsToFetchSelector);
32
+ const scheduledGroups = React.useRef(0);
33
+ const onError = props.unstable_onDataSourceError;
34
+ const [cache, setCache] = React.useState(() => getCache(props.unstable_dataSourceCache));
35
+ const fetchRows = React.useCallback(async parentId => {
36
+ const getRows = props.unstable_dataSource?.getRows;
37
+ if (!getRows) {
38
+ return;
39
+ }
40
+ if (parentId) {
41
+ nestedDataManager.queue([parentId]);
42
+ return;
43
+ }
44
+ nestedDataManager.clear();
45
+ scheduledGroups.current = 0;
46
+ const dataSourceState = apiRef.current.state.dataSource;
47
+ if (dataSourceState !== INITIAL_STATE) {
48
+ apiRef.current.resetDataSourceState();
49
+ }
50
+ const fetchParams = gridGetRowsParamsSelector(apiRef);
51
+ const cachedData = apiRef.current.unstable_dataSource.cache.get(fetchParams);
52
+ if (cachedData !== undefined) {
53
+ const rows = cachedData.rows;
54
+ apiRef.current.setRows(rows);
55
+ if (cachedData.rowCount) {
56
+ apiRef.current.setRowCount(cachedData.rowCount);
57
+ }
58
+ return;
59
+ }
60
+ const isLoading = gridRowsLoadingSelector(apiRef);
61
+ if (!isLoading) {
62
+ apiRef.current.setLoading(true);
63
+ }
64
+ try {
65
+ const getRowsResponse = await getRows(fetchParams);
66
+ apiRef.current.unstable_dataSource.cache.set(fetchParams, getRowsResponse);
67
+ if (getRowsResponse.rowCount) {
68
+ apiRef.current.setRowCount(getRowsResponse.rowCount);
69
+ }
70
+ apiRef.current.setRows(getRowsResponse.rows);
71
+ apiRef.current.setLoading(false);
72
+ } catch (error) {
73
+ apiRef.current.setRows([]);
74
+ apiRef.current.setLoading(false);
75
+ onError?.(error, fetchParams);
76
+ }
77
+ }, [nestedDataManager, apiRef, props.unstable_dataSource?.getRows, onError]);
78
+ const fetchRowChildren = React.useCallback(async id => {
79
+ if (!props.treeData) {
80
+ nestedDataManager.clearPendingRequest(id);
81
+ return;
82
+ }
83
+ const getRows = props.unstable_dataSource?.getRows;
84
+ if (!getRows) {
85
+ nestedDataManager.clearPendingRequest(id);
86
+ return;
87
+ }
88
+ const rowNode = apiRef.current.getRowNode(id);
89
+ if (!rowNode) {
90
+ nestedDataManager.clearPendingRequest(id);
91
+ return;
92
+ }
93
+ const fetchParams = _extends({}, gridGetRowsParamsSelector(apiRef), {
94
+ groupKeys: rowNode.path
95
+ });
96
+ const cachedData = apiRef.current.unstable_dataSource.cache.get(fetchParams);
97
+ if (cachedData !== undefined) {
98
+ const rows = cachedData.rows;
99
+ nestedDataManager.setRequestSettled(id);
100
+ apiRef.current.updateServerRows(rows, rowNode.path);
101
+ if (cachedData.rowCount) {
102
+ apiRef.current.setRowCount(cachedData.rowCount);
103
+ }
104
+ apiRef.current.setRowChildrenExpansion(id, true);
105
+ apiRef.current.unstable_dataSource.setChildrenLoading(id, false);
106
+ return;
107
+ }
108
+ const existingError = gridDataSourceErrorsSelector(apiRef)[id] ?? null;
109
+ if (existingError) {
110
+ apiRef.current.unstable_dataSource.setChildrenFetchError(id, null);
111
+ }
112
+ try {
113
+ const getRowsResponse = await getRows(fetchParams);
114
+ if (!apiRef.current.getRowNode(id)) {
115
+ // The row has been removed from the grid
116
+ nestedDataManager.clearPendingRequest(id);
117
+ return;
118
+ }
119
+ if (nestedDataManager.getRequestStatus(id) === RequestStatus.UNKNOWN) {
120
+ apiRef.current.unstable_dataSource.setChildrenLoading(id, false);
121
+ return;
122
+ }
123
+ nestedDataManager.setRequestSettled(id);
124
+ apiRef.current.unstable_dataSource.cache.set(fetchParams, getRowsResponse);
125
+ if (getRowsResponse.rowCount) {
126
+ apiRef.current.setRowCount(getRowsResponse.rowCount);
127
+ }
128
+ apiRef.current.updateServerRows(getRowsResponse.rows, rowNode.path);
129
+ apiRef.current.setRowChildrenExpansion(id, true);
130
+ } catch (error) {
131
+ const e = error;
132
+ apiRef.current.unstable_dataSource.setChildrenFetchError(id, e);
133
+ onError?.(e, fetchParams);
134
+ } finally {
135
+ apiRef.current.unstable_dataSource.setChildrenLoading(id, false);
136
+ nestedDataManager.setRequestSettled(id);
137
+ }
138
+ }, [nestedDataManager, onError, apiRef, props.treeData, props.unstable_dataSource?.getRows]);
139
+ const setChildrenLoading = React.useCallback((parentId, isLoading) => {
140
+ apiRef.current.setState(state => {
141
+ if (!state.dataSource.loading[parentId] && isLoading === false) {
142
+ return state;
143
+ }
144
+ const newLoadingState = _extends({}, state.dataSource.loading);
145
+ if (isLoading === false) {
146
+ delete newLoadingState[parentId];
147
+ } else {
148
+ newLoadingState[parentId] = isLoading;
149
+ }
150
+ return _extends({}, state, {
151
+ dataSource: _extends({}, state.dataSource, {
152
+ loading: newLoadingState
153
+ })
154
+ });
155
+ });
156
+ }, [apiRef]);
157
+ const setChildrenFetchError = React.useCallback((parentId, error) => {
158
+ apiRef.current.setState(state => {
159
+ const newErrorsState = _extends({}, state.dataSource.errors);
160
+ if (error === null && newErrorsState[parentId] !== undefined) {
161
+ delete newErrorsState[parentId];
162
+ } else {
163
+ newErrorsState[parentId] = error;
164
+ }
165
+ return _extends({}, state, {
166
+ dataSource: _extends({}, state.dataSource, {
167
+ errors: newErrorsState
168
+ })
169
+ });
170
+ });
171
+ }, [apiRef]);
172
+ const resetDataSourceState = React.useCallback(() => {
173
+ apiRef.current.setState(state => {
174
+ return _extends({}, state, {
175
+ dataSource: INITIAL_STATE
176
+ });
177
+ });
178
+ }, [apiRef]);
179
+ const dataSourceApi = {
180
+ unstable_dataSource: {
181
+ setChildrenLoading,
182
+ setChildrenFetchError,
183
+ fetchRows,
184
+ cache
185
+ }
186
+ };
187
+ const dataSourcePrivateApi = {
188
+ fetchRowChildren,
189
+ resetDataSourceState
190
+ };
191
+ useGridApiMethod(apiRef, dataSourceApi, 'public');
192
+ useGridApiMethod(apiRef, dataSourcePrivateApi, 'private');
193
+ useGridApiEventHandler(apiRef, 'sortModelChange', runIfServerMode(props.sortingMode, fetchRows));
194
+ useGridApiEventHandler(apiRef, 'filterModelChange', runIfServerMode(props.filterMode, fetchRows));
195
+ useGridApiEventHandler(apiRef, 'paginationModelChange', runIfServerMode(props.paginationMode, fetchRows));
196
+ const isFirstRender = React.useRef(true);
197
+ React.useEffect(() => {
198
+ if (isFirstRender.current) {
199
+ isFirstRender.current = false;
200
+ return;
201
+ }
202
+ const newCache = getCache(props.unstable_dataSourceCache);
203
+ setCache(prevCache => prevCache !== newCache ? newCache : prevCache);
204
+ }, [props.unstable_dataSourceCache]);
205
+ React.useEffect(() => {
206
+ if (props.unstable_dataSource) {
207
+ apiRef.current.unstable_dataSource.cache.clear();
208
+ apiRef.current.unstable_dataSource.fetchRows();
209
+ }
210
+ }, [apiRef, props.unstable_dataSource]);
211
+ React.useEffect(() => {
212
+ if (groupsToAutoFetch && groupsToAutoFetch.length && scheduledGroups.current < groupsToAutoFetch.length) {
213
+ const groupsToSchedule = groupsToAutoFetch.slice(scheduledGroups.current);
214
+ nestedDataManager.queue(groupsToSchedule);
215
+ scheduledGroups.current = groupsToAutoFetch.length;
216
+ }
217
+ }, [apiRef, nestedDataManager, groupsToAutoFetch]);
218
+ };
@@ -0,0 +1,87 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
2
+ const MAX_CONCURRENT_REQUESTS = Infinity;
3
+ export const runIfServerMode = (modeProp, fn) => () => {
4
+ if (modeProp === 'server') {
5
+ fn();
6
+ }
7
+ };
8
+ export let RequestStatus = /*#__PURE__*/function (RequestStatus) {
9
+ RequestStatus[RequestStatus["QUEUED"] = 0] = "QUEUED";
10
+ RequestStatus[RequestStatus["PENDING"] = 1] = "PENDING";
11
+ RequestStatus[RequestStatus["SETTLED"] = 2] = "SETTLED";
12
+ RequestStatus[RequestStatus["UNKNOWN"] = 3] = "UNKNOWN";
13
+ return RequestStatus;
14
+ }({});
15
+
16
+ /**
17
+ * Fetches row children from the server with option to limit the number of concurrent requests
18
+ * Determines the status of a request based on the enum `RequestStatus`
19
+ * Uses `GridRowId` to uniquely identify a request
20
+ */
21
+ export class NestedDataManager {
22
+ constructor(privateApiRef, maxConcurrentRequests = MAX_CONCURRENT_REQUESTS) {
23
+ this.pendingRequests = new Set();
24
+ this.queuedRequests = new Set();
25
+ this.settledRequests = new Set();
26
+ this.api = void 0;
27
+ this.maxConcurrentRequests = void 0;
28
+ this.processQueue = async () => {
29
+ if (this.queuedRequests.size === 0 || this.pendingRequests.size >= this.maxConcurrentRequests) {
30
+ return;
31
+ }
32
+ const loopLength = Math.min(this.maxConcurrentRequests - this.pendingRequests.size, this.queuedRequests.size);
33
+ if (loopLength === 0) {
34
+ return;
35
+ }
36
+ const fetchQueue = Array.from(this.queuedRequests);
37
+ for (let i = 0; i < loopLength; i += 1) {
38
+ const id = fetchQueue[i];
39
+ this.queuedRequests.delete(id);
40
+ this.pendingRequests.add(id);
41
+ this.api.fetchRowChildren(id);
42
+ }
43
+ };
44
+ this.queue = async ids => {
45
+ const loadingIds = {};
46
+ ids.forEach(id => {
47
+ this.queuedRequests.add(id);
48
+ loadingIds[id] = true;
49
+ });
50
+ this.api.setState(state => _extends({}, state, {
51
+ dataSource: _extends({}, state.dataSource, {
52
+ loading: _extends({}, state.dataSource.loading, loadingIds)
53
+ })
54
+ }));
55
+ this.processQueue();
56
+ };
57
+ this.setRequestSettled = id => {
58
+ this.pendingRequests.delete(id);
59
+ this.settledRequests.add(id);
60
+ this.processQueue();
61
+ };
62
+ this.clear = () => {
63
+ this.queuedRequests.clear();
64
+ Array.from(this.pendingRequests).forEach(id => this.clearPendingRequest(id));
65
+ };
66
+ this.clearPendingRequest = id => {
67
+ this.api.unstable_dataSource.setChildrenLoading(id, false);
68
+ this.pendingRequests.delete(id);
69
+ this.processQueue();
70
+ };
71
+ this.getRequestStatus = id => {
72
+ if (this.pendingRequests.has(id)) {
73
+ return RequestStatus.PENDING;
74
+ }
75
+ if (this.queuedRequests.has(id)) {
76
+ return RequestStatus.QUEUED;
77
+ }
78
+ if (this.settledRequests.has(id)) {
79
+ return RequestStatus.SETTLED;
80
+ }
81
+ return RequestStatus.UNKNOWN;
82
+ };
83
+ this.getActiveRequestsCount = () => this.pendingRequests.size + this.queuedRequests.size;
84
+ this.api = privateApiRef.current;
85
+ this.maxConcurrentRequests = maxConcurrentRequests;
86
+ }
87
+ }