@mui/x-data-grid-generator 7.7.1 → 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.
- package/CHANGELOG.md +100 -1
- package/hooks/index.d.ts +3 -0
- package/hooks/index.js +3 -1
- package/hooks/serverUtils.d.ts +54 -0
- package/hooks/serverUtils.js +345 -0
- package/hooks/useDemoData.d.ts +3 -0
- package/hooks/useDemoData.js +2 -2
- package/hooks/useMockServer.d.ts +16 -0
- package/hooks/useMockServer.js +197 -0
- package/hooks/useQuery.d.ts +97 -128
- package/hooks/useQuery.js +2 -138
- package/index.js +1 -1
- package/modern/hooks/index.js +3 -1
- package/modern/hooks/serverUtils.js +345 -0
- package/modern/hooks/useDemoData.js +2 -2
- package/modern/hooks/useMockServer.js +197 -0
- package/modern/hooks/useQuery.js +2 -138
- package/modern/index.js +1 -1
- package/node/hooks/index.js +27 -1
- package/node/hooks/serverUtils.js +354 -0
- package/node/hooks/useDemoData.js +3 -0
- package/node/hooks/useMockServer.js +207 -0
- package/node/hooks/useQuery.js +5 -142
- package/node/index.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,105 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## 7.8.0
|
|
7
|
+
|
|
8
|
+
_Jun 28, 2024_
|
|
9
|
+
|
|
10
|
+
We'd like to offer a big thanks to the 10 contributors who made this release possible. Here are some highlights ✨:
|
|
11
|
+
|
|
12
|
+
- 🛰 Introduce server-side data source for improved server integration in the Data Grid.
|
|
13
|
+
|
|
14
|
+
Supports server-side pagination, sorting and filtering on plain and tree data, and automatic caching.
|
|
15
|
+
|
|
16
|
+
To enable, provide a `getRows` function to the `unstable_dataSource` prop on the Data Grid component.
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
const dataSource = {
|
|
20
|
+
getRows: async (params: GridServerGetRowsParams) => {
|
|
21
|
+
const data = await fetch(
|
|
22
|
+
`https://api.example.com/data?${new URLSearchParams({
|
|
23
|
+
page: params.page,
|
|
24
|
+
pageSize: params.pageSize,
|
|
25
|
+
sortModel: JSON.stringify(params.sortModel),
|
|
26
|
+
filterModel: JSON.stringify(params.filterModel),
|
|
27
|
+
}).toString()}`,
|
|
28
|
+
);
|
|
29
|
+
return {
|
|
30
|
+
rows: data.rows,
|
|
31
|
+
totalRows: data.totalRows,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
<DataGridPro
|
|
36
|
+
unstable_dataSource={dataSource}
|
|
37
|
+
{...otherProps}
|
|
38
|
+
/>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
See [server-side data documentation](https://mui.com/x/react-data-grid/server-side-data/) for more details.
|
|
42
|
+
|
|
43
|
+
- 📈 Support Date data on the BarChart component
|
|
44
|
+
- ↕️ Support custom column sort icons on the Data Grid
|
|
45
|
+
- 🖱️ Support modifying the expansion trigger on the Tree View components
|
|
46
|
+
|
|
47
|
+
<!--/ HIGHLIGHT_ABOVE_SEPARATOR /-->
|
|
48
|
+
|
|
49
|
+
### Data Grid
|
|
50
|
+
|
|
51
|
+
#### `@mui/x-data-grid@7.8.0`
|
|
52
|
+
|
|
53
|
+
- [DataGrid] Add `columnHeaderSortIcon` slot (#13563) @arminmeh
|
|
54
|
+
- [DataGrid] Fix dimensions lag issue after autosize (#13587) @MBilalShafi
|
|
55
|
+
- [DataGrid] Fix print export failure when `hideFooter` option is set (#13034) @tarunrajput
|
|
56
|
+
|
|
57
|
+
#### `@mui/x-data-grid-pro@7.8.0` [](https://mui.com/r/x-pro-svg-link 'Pro plan')
|
|
58
|
+
|
|
59
|
+
Same changes as in `@mui/x-data-grid@7.8.0`, plus:
|
|
60
|
+
|
|
61
|
+
- [DataGridPro] Fix multi-sorting indicator being cut off (#13625) @KenanYusuf
|
|
62
|
+
- [DataGridPro] Server-side tree data support (#12317) @MBilalShafi
|
|
63
|
+
|
|
64
|
+
#### `@mui/x-data-grid-premium@7.8.0` [](https://mui.com/r/x-premium-svg-link 'Premium plan')
|
|
65
|
+
|
|
66
|
+
Same changes as in `@mui/x-data-grid-pro@7.8.0`.
|
|
67
|
+
|
|
68
|
+
### Date and Time Pickers
|
|
69
|
+
|
|
70
|
+
#### `@mui/x-date-pickers@7.8.0`
|
|
71
|
+
|
|
72
|
+
- [fields] Fix section clearing behavior on Android (#13652) @LukasTy
|
|
73
|
+
|
|
74
|
+
#### `@mui/x-date-pickers-pro@7.8.0` [](https://mui.com/r/x-pro-svg-link 'Pro plan')
|
|
75
|
+
|
|
76
|
+
Same changes as in `@mui/x-date-pickers@7.8.0`.
|
|
77
|
+
|
|
78
|
+
### Charts
|
|
79
|
+
|
|
80
|
+
#### `@mui/x-charts@7.8.0`
|
|
81
|
+
|
|
82
|
+
- [charts] Fix line chart props not passing correct event handlers (#13609) @JCQuintas
|
|
83
|
+
- [charts] Support BarChart with `Date` data (#13471) @alexfauquette
|
|
84
|
+
- [charts] Support RTL for y-axis (#13614) @alexfauquette
|
|
85
|
+
- [charts] Use default values instead of non-null assertion to prevent error being thrown (#13637) @JCQuintas
|
|
86
|
+
|
|
87
|
+
### Tree View
|
|
88
|
+
|
|
89
|
+
#### `@mui/x-tree-view@7.8.0`
|
|
90
|
+
|
|
91
|
+
- [TreeView] Add `expansionTrigger` prop (#13533) @noraleonte
|
|
92
|
+
- [TreeView] Support experimental features from plugin's dependencies (#13632) @flaviendelangle
|
|
93
|
+
|
|
94
|
+
### Docs
|
|
95
|
+
|
|
96
|
+
- [docs] Add callout for `Luxon` `throwOnInvalid` support (#13621) @LukasTy
|
|
97
|
+
- [docs] Add "Overlays" section to the Data Grid documentation (#13624) @KenanYusuf
|
|
98
|
+
|
|
99
|
+
### Core
|
|
100
|
+
|
|
101
|
+
- [core] Add eslint rule to restrict import from `../internals` root (#13633) @JCQuintas
|
|
102
|
+
- [docs-infra] Sync `\_app` folder with monorepo (#13582) @Janpot
|
|
103
|
+
- [license] Allow usage of charts and tree view pro package for old premium licenses (#13619) @flaviendelangle
|
|
104
|
+
|
|
6
105
|
## 7.7.1
|
|
7
106
|
|
|
8
107
|
_Jun 21, 2024_
|
|
@@ -44,7 +143,7 @@ Same changes as in `@mui/x-data-grid-pro@7.7.1`.
|
|
|
44
143
|
- [pickers] Always use the same timezone in the field, the view and the layout components (#13481) @flaviendelangle
|
|
45
144
|
- [pickers] Fix `AdapterDateFnsV3` generated method types (#13464) @alexey-kozlenkov
|
|
46
145
|
- [pickers] Fix controlled `view` behavior (#13552) @LukasTy
|
|
47
|
-
- [TimePicker] Improves RTL verification for the time pickers default views
|
|
146
|
+
- [TimePicker] Improves RTL verification for the time pickers default views (#13447) @arthurbalduini
|
|
48
147
|
|
|
49
148
|
#### `@mui/x-date-pickers-pro@7.7.1` [](https://mui.com/r/x-pro-svg-link 'Pro plan')
|
|
50
149
|
|
package/hooks/index.d.ts
CHANGED
package/hooks/index.js
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { GridRowModel, GridFilterModel, GridSortModel, GridColDef, GridRowId, GridPaginationModel } from '@mui/x-data-grid-pro';
|
|
2
|
+
import { UseDemoDataOptions } from './useDemoData';
|
|
3
|
+
export interface FakeServerResponse {
|
|
4
|
+
returnedRows: GridRowModel[];
|
|
5
|
+
nextCursor?: string;
|
|
6
|
+
hasNextPage?: boolean;
|
|
7
|
+
totalRowCount: number;
|
|
8
|
+
}
|
|
9
|
+
export interface PageInfo {
|
|
10
|
+
totalRowCount?: number;
|
|
11
|
+
nextCursor?: string;
|
|
12
|
+
hasNextPage?: boolean;
|
|
13
|
+
pageSize?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface DefaultServerOptions {
|
|
16
|
+
minDelay: number;
|
|
17
|
+
maxDelay: number;
|
|
18
|
+
useCursorPagination?: boolean;
|
|
19
|
+
}
|
|
20
|
+
export type ServerOptions = Partial<DefaultServerOptions>;
|
|
21
|
+
export interface QueryOptions {
|
|
22
|
+
cursor?: GridRowId;
|
|
23
|
+
page?: number;
|
|
24
|
+
pageSize?: number;
|
|
25
|
+
filterModel?: GridFilterModel;
|
|
26
|
+
sortModel?: GridSortModel;
|
|
27
|
+
firstRowToRender?: number;
|
|
28
|
+
lastRowToRender?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface ServerSideQueryOptions {
|
|
31
|
+
cursor?: GridRowId;
|
|
32
|
+
paginationModel?: GridPaginationModel;
|
|
33
|
+
groupKeys?: string[];
|
|
34
|
+
filterModel?: GridFilterModel;
|
|
35
|
+
sortModel?: GridSortModel;
|
|
36
|
+
firstRowToRender?: number;
|
|
37
|
+
lastRowToRender?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare const DEFAULT_DATASET_OPTIONS: UseDemoDataOptions;
|
|
40
|
+
export declare const disableDelay: any;
|
|
41
|
+
export declare const DEFAULT_SERVER_OPTIONS: DefaultServerOptions;
|
|
42
|
+
/**
|
|
43
|
+
* Simulates server data loading
|
|
44
|
+
*/
|
|
45
|
+
export declare const loadServerRows: (rows: GridRowModel[], queryOptions: QueryOptions, serverOptions: ServerOptions, columnsWithDefaultColDef: GridColDef[]) => Promise<FakeServerResponse>;
|
|
46
|
+
interface ProcessTreeDataRowsResponse {
|
|
47
|
+
rows: GridRowModel[];
|
|
48
|
+
rootRowCount: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Simulates server data loading
|
|
52
|
+
*/
|
|
53
|
+
export declare const processTreeDataRows: (rows: GridRowModel[], queryOptions: ServerSideQueryOptions, serverOptions: ServerOptions, columnsWithDefaultColDef: GridColDef[]) => Promise<ProcessTreeDataRowsResponse>;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import { GridLogicOperator } from '@mui/x-data-grid-pro';
|
|
3
|
+
import { randomInt } from '../services/random-generator';
|
|
4
|
+
export const DEFAULT_DATASET_OPTIONS = {
|
|
5
|
+
dataSet: 'Commodity',
|
|
6
|
+
rowLength: 100,
|
|
7
|
+
maxColumns: 6
|
|
8
|
+
};
|
|
9
|
+
export const disableDelay = typeof DISABLE_CHANCE_RANDOM !== 'undefined' && DISABLE_CHANCE_RANDOM;
|
|
10
|
+
export const DEFAULT_SERVER_OPTIONS = {
|
|
11
|
+
minDelay: disableDelay ? 0 : 100,
|
|
12
|
+
maxDelay: disableDelay ? 0 : 300,
|
|
13
|
+
useCursorPagination: true
|
|
14
|
+
};
|
|
15
|
+
const apiRef = {};
|
|
16
|
+
const simplifiedValueGetter = (field, colDef) => row => {
|
|
17
|
+
return colDef.valueGetter?.(row[row.id], row, colDef, apiRef) || row[field];
|
|
18
|
+
};
|
|
19
|
+
const getRowComparator = (sortModel, columnsWithDefaultColDef) => {
|
|
20
|
+
if (!sortModel) {
|
|
21
|
+
const comparator = () => 0;
|
|
22
|
+
return comparator;
|
|
23
|
+
}
|
|
24
|
+
const sortOperators = sortModel.map(sortItem => {
|
|
25
|
+
const columnField = sortItem.field;
|
|
26
|
+
const colDef = columnsWithDefaultColDef.find(({
|
|
27
|
+
field
|
|
28
|
+
}) => field === columnField);
|
|
29
|
+
return _extends({}, sortItem, {
|
|
30
|
+
valueGetter: simplifiedValueGetter(columnField, colDef),
|
|
31
|
+
sortComparator: colDef.sortComparator
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
const comparator = (row1, row2) => sortOperators.reduce((acc, {
|
|
35
|
+
valueGetter,
|
|
36
|
+
sort,
|
|
37
|
+
sortComparator
|
|
38
|
+
}) => {
|
|
39
|
+
if (acc !== 0) {
|
|
40
|
+
return acc;
|
|
41
|
+
}
|
|
42
|
+
const v1 = valueGetter(row1);
|
|
43
|
+
const v2 = valueGetter(row2);
|
|
44
|
+
return sort === 'desc' ? -1 * sortComparator(v1, v2) : sortComparator(v1, v2);
|
|
45
|
+
}, 0);
|
|
46
|
+
return comparator;
|
|
47
|
+
};
|
|
48
|
+
const buildQuickFilterApplier = (filterModel, columns) => {
|
|
49
|
+
const quickFilterValues = filterModel.quickFilterValues?.filter(Boolean) ?? [];
|
|
50
|
+
if (quickFilterValues.length === 0) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const appliersPerField = [];
|
|
54
|
+
const stubApiRef = {
|
|
55
|
+
current: {
|
|
56
|
+
getRowFormattedValue: (row, c) => {
|
|
57
|
+
const field = c.field;
|
|
58
|
+
return row[field];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
columns.forEach(column => {
|
|
63
|
+
const getApplyQuickFilterFn = column?.getApplyQuickFilterFn;
|
|
64
|
+
if (getApplyQuickFilterFn) {
|
|
65
|
+
appliersPerField.push({
|
|
66
|
+
column,
|
|
67
|
+
appliers: quickFilterValues.map(quickFilterValue => {
|
|
68
|
+
return {
|
|
69
|
+
fn: getApplyQuickFilterFn(quickFilterValue, column, stubApiRef)
|
|
70
|
+
};
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return function isRowMatchingQuickFilter(row, shouldApplyFilter) {
|
|
76
|
+
const result = {};
|
|
77
|
+
|
|
78
|
+
/* eslint-disable no-labels */
|
|
79
|
+
outer: for (let v = 0; v < quickFilterValues.length; v += 1) {
|
|
80
|
+
const filterValue = quickFilterValues[v];
|
|
81
|
+
for (let i = 0; i < appliersPerField.length; i += 1) {
|
|
82
|
+
const {
|
|
83
|
+
column,
|
|
84
|
+
appliers
|
|
85
|
+
} = appliersPerField[i];
|
|
86
|
+
const {
|
|
87
|
+
field
|
|
88
|
+
} = column;
|
|
89
|
+
if (shouldApplyFilter && !shouldApplyFilter(field)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const applier = appliers[v];
|
|
93
|
+
const value = row[field];
|
|
94
|
+
if (applier.fn === null) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const isMatching = applier.fn(value, row, column, stubApiRef);
|
|
98
|
+
if (isMatching) {
|
|
99
|
+
result[filterValue] = true;
|
|
100
|
+
continue outer;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
result[filterValue] = false;
|
|
104
|
+
}
|
|
105
|
+
/* eslint-enable no-labels */
|
|
106
|
+
|
|
107
|
+
return result;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const getQuicklyFilteredRows = (rows, filterModel, columnsWithDefaultColDef) => {
|
|
111
|
+
if (filterModel === undefined || filterModel.quickFilterValues?.length === 0) {
|
|
112
|
+
return rows;
|
|
113
|
+
}
|
|
114
|
+
const isRowMatchingQuickFilter = buildQuickFilterApplier(filterModel, columnsWithDefaultColDef);
|
|
115
|
+
if (isRowMatchingQuickFilter) {
|
|
116
|
+
return rows.filter(row => {
|
|
117
|
+
const result = isRowMatchingQuickFilter(row);
|
|
118
|
+
return filterModel.quickFilterLogicOperator === GridLogicOperator.And ? Object.values(result).every(Boolean) : Object.values(result).some(Boolean);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return rows;
|
|
122
|
+
};
|
|
123
|
+
const getFilteredRows = (rows, filterModel, columnsWithDefaultColDef) => {
|
|
124
|
+
if (filterModel === undefined || filterModel.items.length === 0) {
|
|
125
|
+
return rows;
|
|
126
|
+
}
|
|
127
|
+
const valueGetters = filterModel.items.map(({
|
|
128
|
+
field
|
|
129
|
+
}) => simplifiedValueGetter(field, columnsWithDefaultColDef.find(column => column.field === field)));
|
|
130
|
+
const filterFunctions = filterModel.items.map(filterItem => {
|
|
131
|
+
const {
|
|
132
|
+
field,
|
|
133
|
+
operator
|
|
134
|
+
} = filterItem;
|
|
135
|
+
const colDef = columnsWithDefaultColDef.find(column => column.field === field);
|
|
136
|
+
if (!colDef.filterOperators) {
|
|
137
|
+
throw new Error(`MUI: No filter operator found for column '${field}'.`);
|
|
138
|
+
}
|
|
139
|
+
const filterOperator = colDef.filterOperators.find(({
|
|
140
|
+
value
|
|
141
|
+
}) => operator === value);
|
|
142
|
+
let parsedValue = filterItem.value;
|
|
143
|
+
if (colDef.valueParser) {
|
|
144
|
+
const parser = colDef.valueParser;
|
|
145
|
+
parsedValue = Array.isArray(filterItem.value) ? filterItem.value?.map(x => parser(x, {}, colDef, apiRef)) : parser(filterItem.value, {}, colDef, apiRef);
|
|
146
|
+
}
|
|
147
|
+
return filterOperator.getApplyFilterFn({
|
|
148
|
+
filterItem,
|
|
149
|
+
value: parsedValue
|
|
150
|
+
}, colDef);
|
|
151
|
+
});
|
|
152
|
+
if (filterModel.logicOperator === GridLogicOperator.Or) {
|
|
153
|
+
return rows.filter(row => filterModel.items.some((_, index) => {
|
|
154
|
+
const value = valueGetters[index](row);
|
|
155
|
+
return filterFunctions[index] === null ? true : filterFunctions[index](value);
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
return rows.filter(row => filterModel.items.every((_, index) => {
|
|
159
|
+
const value = valueGetters[index](row);
|
|
160
|
+
return filterFunctions[index] === null ? true : filterFunctions[index](value);
|
|
161
|
+
}));
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Simulates server data loading
|
|
166
|
+
*/
|
|
167
|
+
export const loadServerRows = (rows, queryOptions, serverOptions, columnsWithDefaultColDef) => {
|
|
168
|
+
const {
|
|
169
|
+
minDelay = 100,
|
|
170
|
+
maxDelay = 300,
|
|
171
|
+
useCursorPagination
|
|
172
|
+
} = serverOptions;
|
|
173
|
+
if (maxDelay < minDelay) {
|
|
174
|
+
throw new Error('serverOptions.minDelay is larger than serverOptions.maxDelay ');
|
|
175
|
+
}
|
|
176
|
+
const delay = randomInt(minDelay, maxDelay);
|
|
177
|
+
const {
|
|
178
|
+
cursor,
|
|
179
|
+
page = 0,
|
|
180
|
+
pageSize
|
|
181
|
+
} = queryOptions;
|
|
182
|
+
let nextCursor;
|
|
183
|
+
let firstRowIndex;
|
|
184
|
+
let lastRowIndex;
|
|
185
|
+
let filteredRows = getFilteredRows(rows, queryOptions.filterModel, columnsWithDefaultColDef);
|
|
186
|
+
const rowComparator = getRowComparator(queryOptions.sortModel, columnsWithDefaultColDef);
|
|
187
|
+
filteredRows = [...filteredRows].sort(rowComparator);
|
|
188
|
+
const totalRowCount = filteredRows.length;
|
|
189
|
+
if (!pageSize) {
|
|
190
|
+
firstRowIndex = 0;
|
|
191
|
+
lastRowIndex = filteredRows.length;
|
|
192
|
+
} else if (useCursorPagination) {
|
|
193
|
+
firstRowIndex = cursor ? filteredRows.findIndex(({
|
|
194
|
+
id
|
|
195
|
+
}) => id === cursor) : 0;
|
|
196
|
+
firstRowIndex = Math.max(firstRowIndex, 0); // if cursor not found return 0
|
|
197
|
+
lastRowIndex = firstRowIndex + pageSize;
|
|
198
|
+
nextCursor = lastRowIndex >= filteredRows.length ? undefined : filteredRows[lastRowIndex].id;
|
|
199
|
+
} else {
|
|
200
|
+
firstRowIndex = page * pageSize;
|
|
201
|
+
lastRowIndex = (page + 1) * pageSize;
|
|
202
|
+
}
|
|
203
|
+
const hasNextPage = lastRowIndex < filteredRows.length - 1;
|
|
204
|
+
const response = {
|
|
205
|
+
returnedRows: filteredRows.slice(firstRowIndex, lastRowIndex),
|
|
206
|
+
hasNextPage,
|
|
207
|
+
nextCursor,
|
|
208
|
+
totalRowCount
|
|
209
|
+
};
|
|
210
|
+
return new Promise(resolve => {
|
|
211
|
+
setTimeout(() => {
|
|
212
|
+
resolve(response);
|
|
213
|
+
}, delay); // simulate network latency
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
const findTreeDataRowChildren = (allRows, parentPath, pathKey = 'path', depth = 1 // the depth of the children to find relative to parentDepth, `-1` to find all
|
|
217
|
+
) => {
|
|
218
|
+
const parentDepth = parentPath.length;
|
|
219
|
+
const children = [];
|
|
220
|
+
for (let i = 0; i < allRows.length; i += 1) {
|
|
221
|
+
const row = allRows[i];
|
|
222
|
+
const rowPath = row[pathKey];
|
|
223
|
+
if (!rowPath) {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if ((depth < 0 && rowPath.length > parentDepth || rowPath.length === parentDepth + depth) && parentPath.every((value, index) => value === rowPath[index])) {
|
|
227
|
+
children.push(row);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return children;
|
|
231
|
+
};
|
|
232
|
+
const getTreeDataFilteredRows = (rows, filterModel, columnsWithDefaultColDef) => {
|
|
233
|
+
let filteredRows = [...rows];
|
|
234
|
+
if (filterModel && filterModel.quickFilterValues?.length > 0) {
|
|
235
|
+
filteredRows = getQuicklyFilteredRows(rows, filterModel, columnsWithDefaultColDef);
|
|
236
|
+
}
|
|
237
|
+
if ((filterModel?.items.length ?? 0) > 0) {
|
|
238
|
+
filteredRows = getFilteredRows(filteredRows, filterModel, columnsWithDefaultColDef);
|
|
239
|
+
}
|
|
240
|
+
if (filteredRows.length === rows.length || filteredRows.length === 0) {
|
|
241
|
+
return filteredRows;
|
|
242
|
+
}
|
|
243
|
+
const pathsToIndexesMap = new Map();
|
|
244
|
+
rows.forEach((row, index) => {
|
|
245
|
+
pathsToIndexesMap.set(row.path.join(','), index);
|
|
246
|
+
});
|
|
247
|
+
const includedPaths = new Set();
|
|
248
|
+
filteredRows.forEach(row => {
|
|
249
|
+
includedPaths.add(row.path.join(','));
|
|
250
|
+
});
|
|
251
|
+
const missingChildren = [];
|
|
252
|
+
|
|
253
|
+
// include missing children of filtered rows
|
|
254
|
+
filteredRows.forEach(row => {
|
|
255
|
+
const path = row.path;
|
|
256
|
+
if (path) {
|
|
257
|
+
const children = findTreeDataRowChildren(rows, path, 'path', -1);
|
|
258
|
+
children.forEach(child => {
|
|
259
|
+
const subPath = child.path.join(',');
|
|
260
|
+
if (!includedPaths.has(subPath)) {
|
|
261
|
+
missingChildren.push(child);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
filteredRows = missingChildren.concat(filteredRows);
|
|
267
|
+
const missingParents = [];
|
|
268
|
+
|
|
269
|
+
// include missing parents of filtered rows
|
|
270
|
+
filteredRows.forEach(row => {
|
|
271
|
+
const path = row.path;
|
|
272
|
+
if (path) {
|
|
273
|
+
includedPaths.add(path.join(','));
|
|
274
|
+
for (let i = 0; i < path.length - 1; i += 1) {
|
|
275
|
+
const subPath = path.slice(0, i + 1).join(',');
|
|
276
|
+
if (!includedPaths.has(subPath)) {
|
|
277
|
+
const index = pathsToIndexesMap.get(subPath);
|
|
278
|
+
if (index !== undefined) {
|
|
279
|
+
missingParents.push(rows[index]);
|
|
280
|
+
includedPaths.add(subPath);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
return missingParents.concat(filteredRows);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Simulates server data loading
|
|
291
|
+
*/
|
|
292
|
+
export const processTreeDataRows = (rows, queryOptions, serverOptions, columnsWithDefaultColDef) => {
|
|
293
|
+
const {
|
|
294
|
+
minDelay = 100,
|
|
295
|
+
maxDelay = 300
|
|
296
|
+
} = serverOptions;
|
|
297
|
+
const pathKey = 'path';
|
|
298
|
+
// TODO: Support filtering and cursor based pagination
|
|
299
|
+
if (maxDelay < minDelay) {
|
|
300
|
+
throw new Error('serverOptions.minDelay is larger than serverOptions.maxDelay ');
|
|
301
|
+
}
|
|
302
|
+
if (queryOptions.groupKeys == null) {
|
|
303
|
+
throw new Error('serverOptions.groupKeys must be defined to compute tree data ');
|
|
304
|
+
}
|
|
305
|
+
const delay = randomInt(minDelay, maxDelay);
|
|
306
|
+
|
|
307
|
+
// apply plain filtering
|
|
308
|
+
const filteredRows = getTreeDataFilteredRows(rows, queryOptions.filterModel, columnsWithDefaultColDef);
|
|
309
|
+
|
|
310
|
+
// get root row count
|
|
311
|
+
const rootRowCount = findTreeDataRowChildren(filteredRows, []).length;
|
|
312
|
+
|
|
313
|
+
// find direct children referring to the `parentPath`
|
|
314
|
+
const childRows = findTreeDataRowChildren(filteredRows, queryOptions.groupKeys);
|
|
315
|
+
let childRowsWithDescendantCounts = childRows.map(row => {
|
|
316
|
+
const descendants = findTreeDataRowChildren(filteredRows, row[pathKey], pathKey, -1);
|
|
317
|
+
const descendantCount = descendants.length;
|
|
318
|
+
return _extends({}, row, {
|
|
319
|
+
descendantCount
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
if (queryOptions.sortModel) {
|
|
323
|
+
// apply sorting
|
|
324
|
+
const rowComparator = getRowComparator(queryOptions.sortModel, columnsWithDefaultColDef);
|
|
325
|
+
childRowsWithDescendantCounts = [...childRowsWithDescendantCounts].sort(rowComparator);
|
|
326
|
+
}
|
|
327
|
+
if (queryOptions.paginationModel && queryOptions.groupKeys.length === 0) {
|
|
328
|
+
// Only paginate root rows, grid should refetch root rows when `paginationModel` updates
|
|
329
|
+
const {
|
|
330
|
+
pageSize,
|
|
331
|
+
page
|
|
332
|
+
} = queryOptions.paginationModel;
|
|
333
|
+
if (pageSize < childRowsWithDescendantCounts.length) {
|
|
334
|
+
childRowsWithDescendantCounts = childRowsWithDescendantCounts.slice(page * pageSize, (page + 1) * pageSize);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return new Promise(resolve => {
|
|
338
|
+
setTimeout(() => {
|
|
339
|
+
resolve({
|
|
340
|
+
rows: childRowsWithDescendantCounts,
|
|
341
|
+
rootRowCount
|
|
342
|
+
});
|
|
343
|
+
}, delay); // simulate network latency
|
|
344
|
+
});
|
|
345
|
+
};
|
package/hooks/useDemoData.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GridColumnVisibilityModel } from '@mui/x-data-grid-premium';
|
|
2
|
+
import { GridDemoData } from '../services/real-data-service';
|
|
2
3
|
import { GridColDefGenerator } from '../services/gridColDefGenerator';
|
|
3
4
|
import { AddPathToDemoDataOptions, DemoTreeDataValue } from '../services/tree-data-generator';
|
|
4
5
|
export type DemoDataReturnType = {
|
|
@@ -16,6 +17,8 @@ export interface UseDemoDataOptions {
|
|
|
16
17
|
editable?: boolean;
|
|
17
18
|
treeData?: AddPathToDemoDataOptions;
|
|
18
19
|
}
|
|
20
|
+
export declare function extrapolateSeed(rowLength: number, data: GridDemoData): Promise<GridDemoData>;
|
|
21
|
+
export declare const deepFreeze: <T>(object: T) => T;
|
|
19
22
|
export interface ColumnsOptions extends Pick<UseDemoDataOptions, 'dataSet' | 'editable' | 'maxColumns' | 'visibleFields'> {
|
|
20
23
|
}
|
|
21
24
|
export declare const getColumnsFromOptions: (options: ColumnsOptions) => GridColDefGenerator[];
|
package/hooks/useDemoData.js
CHANGED
|
@@ -12,7 +12,7 @@ const dataCache = new LRUCache({
|
|
|
12
12
|
});
|
|
13
13
|
// Generate fake data from a seed.
|
|
14
14
|
// It's about x20 faster than getRealData.
|
|
15
|
-
async function extrapolateSeed(rowLength, data) {
|
|
15
|
+
export async function extrapolateSeed(rowLength, data) {
|
|
16
16
|
return new Promise(resolve => {
|
|
17
17
|
const seed = data.rows;
|
|
18
18
|
const rows = data.rows.slice();
|
|
@@ -42,7 +42,7 @@ async function extrapolateSeed(rowLength, data) {
|
|
|
42
42
|
});
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
const deepFreeze = object => {
|
|
45
|
+
export const deepFreeze = object => {
|
|
46
46
|
// Retrieve the property names defined on object
|
|
47
47
|
const propNames = Object.getOwnPropertyNames(object);
|
|
48
48
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GridRowModel, GridGetRowsResponse, GridColDef, GridInitialState } from '@mui/x-data-grid-pro';
|
|
2
|
+
import { UseDemoDataOptions } from './useDemoData';
|
|
3
|
+
import type { ServerOptions } from './serverUtils';
|
|
4
|
+
export declare const BASE_URL = "https://mui.com/x/api/data-grid";
|
|
5
|
+
type UseMockServerResponse = {
|
|
6
|
+
columns: GridColDef[];
|
|
7
|
+
initialState: GridInitialState;
|
|
8
|
+
getGroupKey?: (row: GridRowModel) => string;
|
|
9
|
+
getChildrenCount?: (row: GridRowModel) => number;
|
|
10
|
+
fetchRows: (url: string) => Promise<GridGetRowsResponse>;
|
|
11
|
+
loadNewData: () => void;
|
|
12
|
+
};
|
|
13
|
+
export declare const useMockServer: (dataSetOptions?: Partial<UseDemoDataOptions>, serverOptions?: ServerOptions & {
|
|
14
|
+
verbose?: boolean;
|
|
15
|
+
}, shouldRequestsFail?: boolean) => UseMockServerResponse;
|
|
16
|
+
export {};
|