@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
|
@@ -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
|
+
};
|
|
@@ -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,197 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import LRUCache from 'lru-cache';
|
|
4
|
+
import { getGridDefaultColumnTypes } from '@mui/x-data-grid-pro';
|
|
5
|
+
import { getColumnsFromOptions, extrapolateSeed, deepFreeze } from './useDemoData';
|
|
6
|
+
import { getRealGridData } from '../services/real-data-service';
|
|
7
|
+
import { addTreeDataOptionsToDemoData } from '../services/tree-data-generator';
|
|
8
|
+
import { loadServerRows, processTreeDataRows, DEFAULT_DATASET_OPTIONS, DEFAULT_SERVER_OPTIONS } from './serverUtils';
|
|
9
|
+
import { randomInt } from '../services';
|
|
10
|
+
const dataCache = new LRUCache({
|
|
11
|
+
max: 10,
|
|
12
|
+
ttl: 60 * 5 * 1e3 // 5 minutes
|
|
13
|
+
});
|
|
14
|
+
export const BASE_URL = 'https://mui.com/x/api/data-grid';
|
|
15
|
+
function decodeParams(url) {
|
|
16
|
+
const params = new URL(url).searchParams;
|
|
17
|
+
const decodedParams = {};
|
|
18
|
+
const array = Array.from(params.entries());
|
|
19
|
+
for (const [key, value] of array) {
|
|
20
|
+
try {
|
|
21
|
+
decodedParams[key] = JSON.parse(decodeURIComponent(value));
|
|
22
|
+
} catch (e) {
|
|
23
|
+
decodedParams[key] = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return decodedParams;
|
|
27
|
+
}
|
|
28
|
+
const getInitialState = (columns, groupingField) => {
|
|
29
|
+
const columnVisibilityModel = {};
|
|
30
|
+
columns.forEach(col => {
|
|
31
|
+
if (col.hide) {
|
|
32
|
+
columnVisibilityModel[col.field] = false;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (groupingField) {
|
|
36
|
+
columnVisibilityModel[groupingField] = false;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
columns: {
|
|
40
|
+
columnVisibilityModel
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const defaultColDef = getGridDefaultColumnTypes();
|
|
45
|
+
export const useMockServer = (dataSetOptions, serverOptions, shouldRequestsFail) => {
|
|
46
|
+
const [data, setData] = React.useState();
|
|
47
|
+
const [index, setIndex] = React.useState(0);
|
|
48
|
+
const shouldRequestsFailRef = React.useRef(shouldRequestsFail ?? false);
|
|
49
|
+
React.useEffect(() => {
|
|
50
|
+
if (shouldRequestsFail !== undefined) {
|
|
51
|
+
shouldRequestsFailRef.current = shouldRequestsFail;
|
|
52
|
+
}
|
|
53
|
+
}, [shouldRequestsFail]);
|
|
54
|
+
const options = _extends({}, DEFAULT_DATASET_OPTIONS, dataSetOptions);
|
|
55
|
+
const columns = React.useMemo(() => {
|
|
56
|
+
return getColumnsFromOptions({
|
|
57
|
+
dataSet: options.dataSet,
|
|
58
|
+
editable: options.editable,
|
|
59
|
+
maxColumns: options.maxColumns,
|
|
60
|
+
visibleFields: options.visibleFields
|
|
61
|
+
});
|
|
62
|
+
}, [options.dataSet, options.editable, options.maxColumns, options.visibleFields]);
|
|
63
|
+
const initialState = React.useMemo(() => getInitialState(columns, options.treeData?.groupingField), [columns, options.treeData?.groupingField]);
|
|
64
|
+
const columnsWithDefaultColDef = React.useMemo(() => columns.map(column => _extends({}, defaultColDef[column.type || 'string'], column)), [columns]);
|
|
65
|
+
const isTreeData = options.treeData?.groupingField != null;
|
|
66
|
+
const getGroupKey = React.useMemo(() => {
|
|
67
|
+
if (isTreeData) {
|
|
68
|
+
return row => row[options.treeData.groupingField];
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
}, [options.treeData?.groupingField, isTreeData]);
|
|
73
|
+
const getChildrenCount = React.useMemo(() => {
|
|
74
|
+
if (isTreeData) {
|
|
75
|
+
return row => row.descendantCount;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}, [isTreeData]);
|
|
79
|
+
React.useEffect(() => {
|
|
80
|
+
const cacheKey = `${options.dataSet}-${options.rowLength}-${index}-${options.maxColumns}`;
|
|
81
|
+
|
|
82
|
+
// Cache to allow fast switch between the JavaScript and TypeScript version
|
|
83
|
+
// of the demos.
|
|
84
|
+
if (dataCache.has(cacheKey)) {
|
|
85
|
+
const newData = dataCache.get(cacheKey);
|
|
86
|
+
setData(newData);
|
|
87
|
+
return undefined;
|
|
88
|
+
}
|
|
89
|
+
let active = true;
|
|
90
|
+
(async () => {
|
|
91
|
+
let rowData;
|
|
92
|
+
const rowLength = options.rowLength;
|
|
93
|
+
if (rowLength > 1000) {
|
|
94
|
+
rowData = await getRealGridData(1000, columns);
|
|
95
|
+
rowData = await extrapolateSeed(rowLength, rowData);
|
|
96
|
+
} else {
|
|
97
|
+
rowData = await getRealGridData(rowLength, columns);
|
|
98
|
+
}
|
|
99
|
+
if (!active) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (isTreeData) {
|
|
103
|
+
rowData = addTreeDataOptionsToDemoData(rowData, {
|
|
104
|
+
maxDepth: options.treeData?.maxDepth,
|
|
105
|
+
groupingField: options.treeData?.groupingField,
|
|
106
|
+
averageChildren: options.treeData?.averageChildren
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
110
|
+
deepFreeze(rowData);
|
|
111
|
+
}
|
|
112
|
+
dataCache.set(cacheKey, rowData);
|
|
113
|
+
setData(rowData);
|
|
114
|
+
})();
|
|
115
|
+
return () => {
|
|
116
|
+
active = false;
|
|
117
|
+
};
|
|
118
|
+
}, [columns, isTreeData, options.rowLength, options.treeData?.maxDepth, options.treeData?.groupingField, options.treeData?.averageChildren, options.dataSet, options.maxColumns, index]);
|
|
119
|
+
const fetchRows = React.useCallback(async requestUrl => {
|
|
120
|
+
if (!data || !requestUrl) {
|
|
121
|
+
return new Promise(resolve => {
|
|
122
|
+
resolve({
|
|
123
|
+
rows: [],
|
|
124
|
+
rowCount: 0
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const params = decodeParams(requestUrl);
|
|
129
|
+
const verbose = serverOptions?.verbose ?? true;
|
|
130
|
+
// eslint-disable-next-line no-console
|
|
131
|
+
const print = console.info;
|
|
132
|
+
if (verbose) {
|
|
133
|
+
print('MUI X: DATASOURCE REQUEST', params);
|
|
134
|
+
}
|
|
135
|
+
let getRowsResponse;
|
|
136
|
+
const serverOptionsWithDefault = {
|
|
137
|
+
minDelay: serverOptions?.minDelay ?? DEFAULT_SERVER_OPTIONS.minDelay,
|
|
138
|
+
maxDelay: serverOptions?.maxDelay ?? DEFAULT_SERVER_OPTIONS.maxDelay,
|
|
139
|
+
useCursorPagination: serverOptions?.useCursorPagination ?? DEFAULT_SERVER_OPTIONS.useCursorPagination
|
|
140
|
+
};
|
|
141
|
+
if (shouldRequestsFailRef.current) {
|
|
142
|
+
const {
|
|
143
|
+
minDelay,
|
|
144
|
+
maxDelay
|
|
145
|
+
} = serverOptionsWithDefault;
|
|
146
|
+
const delay = randomInt(minDelay, maxDelay);
|
|
147
|
+
return new Promise((_, reject) => {
|
|
148
|
+
if (verbose) {
|
|
149
|
+
print('MUI X: DATASOURCE REQUEST FAILURE', params);
|
|
150
|
+
}
|
|
151
|
+
setTimeout(() => reject(new Error('Could not fetch the data')), delay);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (isTreeData /* || TODO: `isRowGrouping` */) {
|
|
155
|
+
const {
|
|
156
|
+
rows,
|
|
157
|
+
rootRowCount
|
|
158
|
+
} = await processTreeDataRows(data.rows, params, serverOptionsWithDefault, columnsWithDefaultColDef);
|
|
159
|
+
getRowsResponse = {
|
|
160
|
+
rows: rows.slice().map(row => _extends({}, row, {
|
|
161
|
+
path: undefined
|
|
162
|
+
})),
|
|
163
|
+
rowCount: rootRowCount
|
|
164
|
+
};
|
|
165
|
+
} else {
|
|
166
|
+
// plain data
|
|
167
|
+
const {
|
|
168
|
+
returnedRows,
|
|
169
|
+
nextCursor,
|
|
170
|
+
totalRowCount
|
|
171
|
+
} = await loadServerRows(data.rows, _extends({}, params, params.paginationModel), serverOptionsWithDefault, columnsWithDefaultColDef);
|
|
172
|
+
getRowsResponse = {
|
|
173
|
+
rows: returnedRows,
|
|
174
|
+
rowCount: totalRowCount,
|
|
175
|
+
pageInfo: {
|
|
176
|
+
nextCursor
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return new Promise(resolve => {
|
|
181
|
+
if (verbose) {
|
|
182
|
+
print('MUI X: DATASOURCE RESPONSE', params, getRowsResponse);
|
|
183
|
+
}
|
|
184
|
+
resolve(getRowsResponse);
|
|
185
|
+
});
|
|
186
|
+
}, [data, serverOptions?.verbose, serverOptions?.minDelay, serverOptions?.maxDelay, serverOptions?.useCursorPagination, isTreeData, columnsWithDefaultColDef]);
|
|
187
|
+
return {
|
|
188
|
+
columns: columnsWithDefaultColDef,
|
|
189
|
+
initialState,
|
|
190
|
+
getGroupKey,
|
|
191
|
+
getChildrenCount,
|
|
192
|
+
fetchRows,
|
|
193
|
+
loadNewData: () => {
|
|
194
|
+
setIndex(oldIndex => oldIndex + 1);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
};
|
package/modern/hooks/useQuery.js
CHANGED
|
@@ -1,145 +1,9 @@
|
|
|
1
1
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { getGridDefaultColumnTypes
|
|
3
|
+
import { getGridDefaultColumnTypes } from '@mui/x-data-grid-pro';
|
|
4
4
|
import { isDeepEqual } from '@mui/x-data-grid/internals';
|
|
5
5
|
import { useDemoData, getColumnsFromOptions, getInitialState } from './useDemoData';
|
|
6
|
-
import {
|
|
7
|
-
const apiRef = {};
|
|
8
|
-
const simplifiedValueGetter = (field, colDef) => row => {
|
|
9
|
-
return colDef.valueGetter?.(row[row.id], row, colDef, apiRef) || row[field];
|
|
10
|
-
};
|
|
11
|
-
const getRowComparator = (sortModel, columnsWithDefaultColDef) => {
|
|
12
|
-
if (!sortModel) {
|
|
13
|
-
const comparator = () => 0;
|
|
14
|
-
return comparator;
|
|
15
|
-
}
|
|
16
|
-
const sortOperators = sortModel.map(sortItem => {
|
|
17
|
-
const columnField = sortItem.field;
|
|
18
|
-
const colDef = columnsWithDefaultColDef.find(({
|
|
19
|
-
field
|
|
20
|
-
}) => field === columnField);
|
|
21
|
-
return _extends({}, sortItem, {
|
|
22
|
-
valueGetter: simplifiedValueGetter(columnField, colDef),
|
|
23
|
-
sortComparator: colDef.sortComparator
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
const comparator = (row1, row2) => sortOperators.reduce((acc, {
|
|
27
|
-
valueGetter,
|
|
28
|
-
sort,
|
|
29
|
-
sortComparator
|
|
30
|
-
}) => {
|
|
31
|
-
if (acc !== 0) {
|
|
32
|
-
return acc;
|
|
33
|
-
}
|
|
34
|
-
const v1 = valueGetter(row1);
|
|
35
|
-
const v2 = valueGetter(row2);
|
|
36
|
-
return sort === 'desc' ? -1 * sortComparator(v1, v2) : sortComparator(v1, v2);
|
|
37
|
-
}, 0);
|
|
38
|
-
return comparator;
|
|
39
|
-
};
|
|
40
|
-
const getFilteredRows = (rows, filterModel, columnsWithDefaultColDef) => {
|
|
41
|
-
if (filterModel === undefined || filterModel.items.length === 0) {
|
|
42
|
-
return rows;
|
|
43
|
-
}
|
|
44
|
-
const valueGetters = filterModel.items.map(({
|
|
45
|
-
field
|
|
46
|
-
}) => simplifiedValueGetter(field, columnsWithDefaultColDef.find(column => column.field === field)));
|
|
47
|
-
const filterFunctions = filterModel.items.map(filterItem => {
|
|
48
|
-
const {
|
|
49
|
-
field,
|
|
50
|
-
operator
|
|
51
|
-
} = filterItem;
|
|
52
|
-
const colDef = columnsWithDefaultColDef.find(column => column.field === field);
|
|
53
|
-
const filterOperator = colDef.filterOperators.find(({
|
|
54
|
-
value
|
|
55
|
-
}) => operator === value);
|
|
56
|
-
let parsedValue = filterItem.value;
|
|
57
|
-
if (colDef.valueParser) {
|
|
58
|
-
const parser = colDef.valueParser;
|
|
59
|
-
parsedValue = Array.isArray(filterItem.value) ? filterItem.value?.map(x => parser(x)) : parser(filterItem.value);
|
|
60
|
-
}
|
|
61
|
-
return filterOperator?.getApplyFilterFn({
|
|
62
|
-
filterItem,
|
|
63
|
-
value: parsedValue
|
|
64
|
-
}, colDef);
|
|
65
|
-
});
|
|
66
|
-
if (filterModel.logicOperator === GridLogicOperator.Or) {
|
|
67
|
-
return rows.filter(row => filterModel.items.some((_, index) => {
|
|
68
|
-
const value = valueGetters[index](row);
|
|
69
|
-
return filterFunctions[index] === null ? true : filterFunctions[index]({
|
|
70
|
-
value
|
|
71
|
-
});
|
|
72
|
-
}));
|
|
73
|
-
}
|
|
74
|
-
return rows.filter(row => filterModel.items.every((_, index) => {
|
|
75
|
-
const value = valueGetters[index](row);
|
|
76
|
-
return filterFunctions[index] === null ? true : filterFunctions[index](value);
|
|
77
|
-
}));
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Simulates server data loading
|
|
82
|
-
*/
|
|
83
|
-
export const loadServerRows = (rows, queryOptions, serverOptions, columnsWithDefaultColDef) => {
|
|
84
|
-
const {
|
|
85
|
-
minDelay = 100,
|
|
86
|
-
maxDelay = 300,
|
|
87
|
-
useCursorPagination
|
|
88
|
-
} = serverOptions;
|
|
89
|
-
if (maxDelay < minDelay) {
|
|
90
|
-
throw new Error('serverOptions.minDelay is larger than serverOptions.maxDelay ');
|
|
91
|
-
}
|
|
92
|
-
const delay = randomInt(minDelay, maxDelay);
|
|
93
|
-
const {
|
|
94
|
-
cursor,
|
|
95
|
-
page = 0,
|
|
96
|
-
pageSize
|
|
97
|
-
} = queryOptions;
|
|
98
|
-
let nextCursor;
|
|
99
|
-
let firstRowIndex;
|
|
100
|
-
let lastRowIndex;
|
|
101
|
-
let filteredRows = getFilteredRows(rows, queryOptions.filterModel, columnsWithDefaultColDef);
|
|
102
|
-
const rowComparator = getRowComparator(queryOptions.sortModel, columnsWithDefaultColDef);
|
|
103
|
-
filteredRows = [...filteredRows].sort(rowComparator);
|
|
104
|
-
const totalRowCount = filteredRows.length;
|
|
105
|
-
if (!pageSize) {
|
|
106
|
-
firstRowIndex = 0;
|
|
107
|
-
lastRowIndex = filteredRows.length;
|
|
108
|
-
} else if (useCursorPagination) {
|
|
109
|
-
firstRowIndex = cursor ? filteredRows.findIndex(({
|
|
110
|
-
id
|
|
111
|
-
}) => id === cursor) : 0;
|
|
112
|
-
firstRowIndex = Math.max(firstRowIndex, 0); // if cursor not found return 0
|
|
113
|
-
lastRowIndex = firstRowIndex + pageSize;
|
|
114
|
-
nextCursor = lastRowIndex >= filteredRows.length ? undefined : filteredRows[lastRowIndex].id;
|
|
115
|
-
} else {
|
|
116
|
-
firstRowIndex = page * pageSize;
|
|
117
|
-
lastRowIndex = (page + 1) * pageSize;
|
|
118
|
-
}
|
|
119
|
-
const hasNextPage = lastRowIndex < filteredRows.length - 1;
|
|
120
|
-
const response = {
|
|
121
|
-
returnedRows: filteredRows.slice(firstRowIndex, lastRowIndex),
|
|
122
|
-
nextCursor,
|
|
123
|
-
hasNextPage,
|
|
124
|
-
totalRowCount
|
|
125
|
-
};
|
|
126
|
-
return new Promise(resolve => {
|
|
127
|
-
setTimeout(() => {
|
|
128
|
-
resolve(response);
|
|
129
|
-
}, delay); // simulate network latency
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
|
-
const DEFAULT_DATASET_OPTIONS = {
|
|
133
|
-
dataSet: 'Commodity',
|
|
134
|
-
rowLength: 100,
|
|
135
|
-
maxColumns: 6
|
|
136
|
-
};
|
|
137
|
-
const disableDelay = typeof DISABLE_CHANCE_RANDOM !== 'undefined' && DISABLE_CHANCE_RANDOM;
|
|
138
|
-
const DEFAULT_SERVER_OPTIONS = {
|
|
139
|
-
minDelay: disableDelay ? 0 : 100,
|
|
140
|
-
maxDelay: disableDelay ? 0 : 300,
|
|
141
|
-
useCursorPagination: true
|
|
142
|
-
};
|
|
6
|
+
import { DEFAULT_DATASET_OPTIONS, DEFAULT_SERVER_OPTIONS, loadServerRows } from './serverUtils';
|
|
143
7
|
export const createFakeServer = (dataSetOptions, serverOptions) => {
|
|
144
8
|
const dataSetOptionsWithDefault = _extends({}, DEFAULT_DATASET_OPTIONS, dataSetOptions);
|
|
145
9
|
const serverOptionsWithDefault = _extends({}, DEFAULT_SERVER_OPTIONS, serverOptions);
|