@redsift/table 11.6.0-muiv5-alpha.5 → 11.6.0-muiv5-alpha.7

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.
@@ -1,19 +1,1422 @@
1
- import { Comp } from '@redsift/design-system';
2
- import { D as DataGridProps } from './types.js';
3
-
4
- interface StatefulDataGridProps extends DataGridProps {
5
- /** Hook returning pathname, search params and a method to update query params. */
6
- useRouter: () => {
7
- pathname: string;
8
- search: string;
9
- historyReplace: (newSearch: string) => void;
1
+ import { _ as _objectSpread2, b as _objectWithoutProperties, a as _extends } from './_rollupPluginBabelHelpers.js';
2
+ import React__default, { useCallback, useEffect, useMemo, forwardRef, useRef, useState } from 'react';
3
+ import classNames from 'classnames';
4
+ import { useTheme, ThemeProvider, RedsiftColorBlueN, RedsiftColorNeutralXDarkGrey, RedsiftColorNeutralWhite } from '@redsift/design-system';
5
+ import { GridLinkOperator, useGridApiRef, DataGridPro, gridPaginatedVisibleSortedGridRowEntriesSelector, gridPaginatedVisibleSortedGridRowIdsSelector, gridFilteredSortedRowEntriesSelector, gridFilteredSortedRowIdsSelector } from '@mui/x-data-grid-pro';
6
+ import { o as operatorList, L as LicenseInfo, G as useControlledDatagridState, T as ThemeProvider$1, J as StyledDataGrid, f as customColumnTypes } from './useControlledDatagridState.js';
7
+ import { g as createTheme } from './Portal.js';
8
+ import { T as Toolbar } from './Toolbar2.js';
9
+ import { o as onServerSideSelectionStatusChange, S as ServerSideControlledPagination, C as ControlledPagination } from './ControlledPagination.js';
10
+ import { B as BaseButton, a as BaseCheckbox, c as BasePopper, b as BaseIcon } from './BasePopper.js';
11
+ import { T as ToolbarWrapper } from './ToolbarWrapper2.js';
12
+
13
+ const PAGINATION_MODEL_KEY = 'paginationModel';
14
+ const FILTER_MODEL_KEY = 'filterModel';
15
+ const SORT_MODEL_KEY = 'sortModel';
16
+ const VISIBILITY_MODEL_KEY = 'visibilityModel';
17
+ const PINNED_COLUMNS = 'pinnedColumns';
18
+ const DIMENSION_MODEL_KEY = 'dimension';
19
+ const FILTER_SEARCH_KEY = 'searchModel';
20
+ const CATEGORIES = [PAGINATION_MODEL_KEY, FILTER_MODEL_KEY, SORT_MODEL_KEY, VISIBILITY_MODEL_KEY, DIMENSION_MODEL_KEY, FILTER_SEARCH_KEY, PINNED_COLUMNS];
21
+ const buildStorageKey = _ref => {
22
+ let {
23
+ id,
24
+ version,
25
+ category
26
+ } = _ref;
27
+ return `${id}:${version}:${category}`;
28
+ };
29
+ const clearPreviousVersionStorage = (id, previousLocalStorageVersions) => {
30
+ for (const version of previousLocalStorageVersions) {
31
+ const keysToDelete = [buildStorageKey({
32
+ id,
33
+ version,
34
+ category: PAGINATION_MODEL_KEY
35
+ }), buildStorageKey({
36
+ id,
37
+ version,
38
+ category: SORT_MODEL_KEY
39
+ }), buildStorageKey({
40
+ id,
41
+ version,
42
+ category: FILTER_MODEL_KEY
43
+ }), buildStorageKey({
44
+ id,
45
+ version,
46
+ category: VISIBILITY_MODEL_KEY
47
+ }), buildStorageKey({
48
+ id,
49
+ version,
50
+ category: PINNED_COLUMNS
51
+ }), buildStorageKey({
52
+ id,
53
+ version,
54
+ category: FILTER_SEARCH_KEY
55
+ }), buildStorageKey({
56
+ id,
57
+ version,
58
+ category: DIMENSION_MODEL_KEY
59
+ })];
60
+ for (const keyToDelete of keysToDelete) {
61
+ try {
62
+ window.localStorage.removeItem(keyToDelete);
63
+ } catch (e) {
64
+ // Ignore
65
+ }
66
+ }
67
+ }
68
+ };
69
+
70
+ // reference value: https://www.w3schools.com/tags/ref_urlencode.ASP
71
+ const DECODER = {
72
+ '%20': ' ',
73
+ '%26': '&',
74
+ '%3D': '=',
75
+ '%3F': '?',
76
+ '%5B': '[',
77
+ '%5D': ']',
78
+ '%2C': ',',
79
+ '%3C': '<',
80
+ '%3E': '>',
81
+ '%21': '!',
82
+ '%22': '"'
83
+ };
84
+ const ENCODER = {
85
+ ' ': '%20',
86
+ '&': '%26',
87
+ '=': '%3D',
88
+ '?': '%3F',
89
+ '[': '%5B',
90
+ ']': '%5D',
91
+ ',': '%2C',
92
+ '<': '%3C',
93
+ '>': '%3E',
94
+ '!': '%21',
95
+ '"': '%22'
96
+ };
97
+ const decodeValue = value => {
98
+ if (value === '') {
99
+ return '';
100
+ }
101
+ const re = new RegExp(Object.keys(DECODER).reduce((acc, curr) => `${acc}|${curr}`), 'g');
102
+ // decodeValue for lists:
103
+ if (value.startsWith('list[')) {
104
+ const arrayValues = value.split('[')[1].split(']')[0];
105
+ const arrayList = arrayValues.split(',').map(v => v.replace(re, encoded => DECODER[encoded])).filter(item => item);
106
+ return arrayList.length > 0 ? arrayList : [];
107
+ }
108
+ return value.replace(re, encoded => DECODER[encoded]);
109
+ };
110
+ const encodeValue = value => {
111
+ if (!value) {
112
+ return '';
113
+ }
114
+
115
+ // Array encoding for value:
116
+ // we are representing it as list[encoded], where encoded is the list comma separated
117
+ if (Array.isArray(value)) {
118
+ const encodedArray = value.map(entry => {
119
+ return String(entry).replace(/\s|&|=|\?|\[|\]/g, encoded => ENCODER[encoded]);
120
+ }).join(',');
121
+ return `list[${encodedArray}]`;
122
+ }
123
+
124
+ // we might also pass integers
125
+ const castedValue = String(value);
126
+ return castedValue.replace(/\s|&|=|\?|\[|\]/g, encoded => ENCODER[encoded]);
127
+ };
128
+ const urlSearchParamsToString = searchParams => {
129
+ let searchString = '';
130
+ for (const [key, value] of searchParams) {
131
+ searchString = searchString + `${key}=${value}&`;
132
+ }
133
+ return searchString.slice(0, searchString.length - 1);
134
+ };
135
+ const numberOperatorEncoder = {
136
+ '=': 'eq',
137
+ '!=': 'ne',
138
+ '>': 'gt',
139
+ '>=': 'gte',
140
+ '<': 'lt',
141
+ '<=': 'lte'
142
+ };
143
+ const numberOperatorDecoder = {
144
+ eq: '=',
145
+ ne: '!=',
146
+ gt: '>',
147
+ gte: '>=',
148
+ lt: '<',
149
+ lte: '<='
150
+ };
151
+ const isOperatorValueValid = (columnField, operatorValue, columns) => {
152
+ const column = columns.find(column => column.field === columnField);
153
+ if (!column) {
154
+ return false;
155
+ }
156
+ const columnType = (column === null || column === void 0 ? void 0 : column.type) || 'string';
157
+ const operators = operatorList[columnType];
158
+ if (!operators) {
159
+ return false;
160
+ }
161
+ if ('filterOperators' in operators) {
162
+ return !!operators.filterOperators.find(op => columnType === 'number' && Object.keys(numberOperatorEncoder).includes(op.value) ? numberOperatorEncoder[op.value] === operatorValue : op['value'] === operatorValue);
163
+ }
164
+ return !!operators.find(op => ['number', 'rsNumber'].includes(columnType) && Object.keys(numberOperatorEncoder).includes(op.value) ? numberOperatorEncoder[op.value] === operatorValue : op['value'] === operatorValue);
165
+ };
166
+ const listOperators = ['containsAnyOf', 'doesNotContainAnyOf', 'endsWithAnyOf', 'doesNotEndWithAnyOf', 'hasAnyOf', 'doesNotHaveAnyOf', 'isAnyOf', 'isNotAnyOf', 'startsWithAnyOf', 'doesNotStartWithAnyOf'];
167
+
168
+ // Check if the value doesn't break
169
+ const isValueValid = (value, columnField, columns, operatorValue) => {
170
+ var _column$type;
171
+ // every field accepts undefined as value for default
172
+ if (value === undefined || value === '') {
173
+ return true;
174
+ }
175
+
176
+ // xxxAnyOf accepts as value only lists, and we are declearing them in the
177
+ // URL as `list=[...]`
178
+ if (listOperators.includes(operatorValue)) {
179
+ return Array.isArray(value) || value === '';
180
+ }
181
+
182
+ // We are accepting arrays only if they are of the 'xxxAnyOf' type
183
+ if (Array.isArray(value) && !listOperators.includes(operatorValue)) {
184
+ return false;
185
+ }
186
+ const column = columns.find(column => column.field === columnField);
187
+ if (!column) {
188
+ return false;
189
+ }
190
+ const type = (_column$type = column['type']) !== null && _column$type !== void 0 ? _column$type : 'string';
191
+
192
+ // Only date and rating fail with 500s, other set themselves as undefined
193
+ if (type !== 'date' && type !== 'rating') {
194
+ return true;
195
+ }
196
+
197
+ // just checking that rating is a number.
198
+ if (type === 'rating') {
199
+ return !isNaN(Number(value));
200
+ }
201
+
202
+ // format: YYYY-MM-DD
203
+ // just verifying that the 3 values are numbers to avoid 500s,
204
+ // If the value is invalid the form will appear as undefined
205
+ if (type === 'date') {
206
+ const dateSplitted = value.split('-');
207
+ if (dateSplitted.length !== 3) {
208
+ return false;
209
+ }
210
+ const [YYYY, MM, DD] = dateSplitted;
211
+ return !isNaN(parseInt(YYYY)) && !isNaN(parseInt(MM)) && !isNaN(parseInt(DD));
212
+ }
213
+ return false;
214
+ };
215
+
216
+ /** FILTERS */
217
+
218
+ // example:
219
+ // unicodeDomain[contains]=a&unicodeDomain[contains]=dsa&logicOperator=and&tab=ignored
220
+ const getFilterModelFromString = (searchString, columns) => {
221
+ if (!searchString) {
222
+ return 'invalid';
223
+ }
224
+ let linkOperator = GridLinkOperator.And;
225
+ let quickFilterValues = [];
226
+ const searchParams = new URLSearchParams();
227
+ for (const [key, value] of new URLSearchParams(searchString)) {
228
+ if (key.startsWith('_') && !['_logicOperator', '_sortColumn', '_pinnedColumnsLeft', '_pinnedColumnsRight', '_columnVisibility', '_pagination', '_quickFilterValues'].includes(key)) {
229
+ searchParams.set(key, value);
230
+ }
231
+ if (key === '_logicOperator') {
232
+ linkOperator = value;
233
+ }
234
+ if (key === '_quickFilterValues') {
235
+ try {
236
+ quickFilterValues = JSON.parse(decodeURIComponent(value));
237
+ } catch {
238
+ quickFilterValues = [];
239
+ }
240
+ }
241
+ }
242
+ let id = 5000;
243
+ const fields = columns.map(column => column.field);
244
+ let isInvalid = false;
245
+ const items = [];
246
+ searchParams.forEach((value, key) => {
247
+ var _columns$find;
248
+ if (isInvalid) {
249
+ return;
250
+ }
251
+ const field = key.split('[')[0].slice(1); // Slice to remove the _ at the beginning
252
+ if (!fields.includes(field)) {
253
+ return;
254
+ }
255
+ const columnType = (_columns$find = columns.find(column => column.field === field)) === null || _columns$find === void 0 ? void 0 : _columns$find.type;
256
+ const left = key.split(']')[0];
257
+ if (left.split('[').length < 2) {
258
+ isInvalid = true;
259
+ return;
260
+ }
261
+ const splitRight = key.split('[')[1].split(']')[0].split(',');
262
+ const type = splitRight[1];
263
+ if (type !== columnType) {
264
+ isInvalid = true;
265
+ return;
266
+ }
267
+ const operator = splitRight[0];
268
+ // if the operator is not part of the valid operators invalidate the URL
269
+ if (!isOperatorValueValid(field, operator, columns) || Array.isArray(operator)) {
270
+ isInvalid = true;
271
+ return;
272
+ }
273
+ id += 1;
274
+ const decodedValue = decodeValue(value);
275
+ if (!isValueValid(decodedValue, field, columns, operator)) {
276
+ isInvalid = true;
277
+ return;
278
+ }
279
+ items.push({
280
+ columnField: field,
281
+ operatorValue: ['number', 'rsNumber'].includes(columnType) && Object.keys(numberOperatorDecoder).includes(operator) ? numberOperatorDecoder[operator] : operator,
282
+ id,
283
+ value: listOperators.includes(operator) && decodedValue === '' ? [] : decodedValue,
284
+ type
285
+ });
286
+ });
287
+
288
+ // If we found some condition that results in an invalid URL,
289
+ // return the empty filterModel (this will trigger the localStorage)
290
+ // and will pick up the last valid search
291
+ if (isInvalid) {
292
+ return 'invalid';
293
+ }
294
+ return {
295
+ items,
296
+ linkOperator,
297
+ quickFilterValues
298
+ };
299
+ };
300
+ const getSearchParamsFromFilterModel = filterModel => {
301
+ var _filterModel$quickFil;
302
+ const searchParams = new URLSearchParams();
303
+ searchParams.set('_logicOperator', filterModel['linkOperator'] || '');
304
+ filterModel['items'].forEach(item => {
305
+ const {
306
+ columnField,
307
+ operatorValue,
308
+ value,
309
+ type
310
+ } = item;
311
+ if (Object.keys(numberOperatorEncoder).includes(operatorValue)) {
312
+ searchParams.set(`_${columnField}[${numberOperatorEncoder[operatorValue]},${encodeValue(type)}]`, encodeValue(value));
313
+ } else {
314
+ searchParams.set(`_${columnField}[${encodeValue(operatorValue)},${encodeValue(type)}]`, encodeValue(value));
315
+ }
316
+ });
317
+ if ((_filterModel$quickFil = filterModel.quickFilterValues) !== null && _filterModel$quickFil !== void 0 && _filterModel$quickFil.length) {
318
+ searchParams.set('_quickFilterValues', encodeURIComponent(JSON.stringify(filterModel.quickFilterValues)));
319
+ }
320
+ return searchParams;
321
+ };
322
+
323
+ // Rules:
324
+ // - if we have something in the URL, use that info
325
+ // - if we don't have that, use the localStorage and update the URL
326
+ // - if we don't have that, return an empty FilterModel
327
+ const getFilterModel = (search, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion) => {
328
+ const defaultValue = initialState && initialState.filter && initialState.filter.filterModel ? initialState.filter.filterModel : {
329
+ items: [],
330
+ linkOperator: GridLinkOperator.And
331
+ };
332
+ if (isNewVersion) {
333
+ return defaultValue;
334
+ }
335
+ const filterModelFromSearch = getFilterModelFromString(search, columns);
336
+ if (filterModelFromSearch !== 'invalid') {
337
+ const searchFromFilterModel = getSearchParamsFromFilterModel(filterModelFromSearch);
338
+ const searchString = urlSearchParamsToString(searchFromFilterModel);
339
+ if (searchString !== localStorageFilters) {
340
+ setLocalStorageFilters(searchString);
341
+ }
342
+ return filterModelFromSearch;
343
+ }
344
+ const filterModelFromLocalStorage = getFilterModelFromString(localStorageFilters, columns);
345
+ if (filterModelFromLocalStorage !== 'invalid') {
346
+ return filterModelFromLocalStorage;
347
+ }
348
+ return defaultValue;
349
+ };
350
+
351
+ /** SORT */
352
+
353
+ const getSortingFromString = (searchString, columns) => {
354
+ if (!searchString) {
355
+ return 'invalid';
356
+ }
357
+ const searchParams = new URLSearchParams(searchString);
358
+ const value = searchParams.get('_sortColumn');
359
+ if (value === '' || value === null || value === '[]') {
360
+ return [];
361
+ }
362
+ const fields = columns.map(column => column.field);
363
+ const [column, order] = value.slice(1, value.length - 1).split(',');
364
+ if (fields.includes(column) && (order === 'asc' || order === 'desc')) {
365
+ return [{
366
+ field: column,
367
+ sort: order
368
+ }];
369
+ }
370
+ return 'invalid';
371
+ };
372
+ const getSearchParamsFromSorting = sorting => {
373
+ const searchParams = new URLSearchParams();
374
+ searchParams.set('_sortColumn', sorting.length > 0 && sorting[0].sort ? `[${encodeValue(sorting[0].field)},${encodeValue(sorting[0].sort)}]` : '[]');
375
+ return searchParams;
376
+ };
377
+
378
+ // Rules:
379
+ // - if we have something in the URL, use that info
380
+ // - if we don't have that, use the localStorage and update the URL
381
+ // - if we don't have that, return an empty SortModel
382
+ const getSortModel = (search, columns, localStorageSorting, setLocalStorageSorting, initialState, isNewVersion) => {
383
+ var _initialState$sorting;
384
+ const defaultValue = initialState !== null && initialState !== void 0 && (_initialState$sorting = initialState.sorting) !== null && _initialState$sorting !== void 0 && _initialState$sorting.sortModel ? initialState.sorting.sortModel : [];
385
+ if (isNewVersion) {
386
+ return defaultValue;
387
+ }
388
+ const sorting = getSortingFromString(search, columns);
389
+ if (sorting !== 'invalid') {
390
+ const searchFromSortModel = getSearchParamsFromSorting(sorting);
391
+ const searchString = urlSearchParamsToString(searchFromSortModel);
392
+ if (searchString !== localStorageSorting) {
393
+ setLocalStorageSorting(searchString);
394
+ }
395
+ return sorting;
396
+ }
397
+ const sortModelFromLocalStorage = getSortingFromString(localStorageSorting, columns);
398
+ if (sortModelFromLocalStorage !== 'invalid') {
399
+ return sortModelFromLocalStorage;
400
+ }
401
+ return defaultValue;
402
+ };
403
+
404
+ /** PAGINATION */
405
+
406
+ const getPaginationFromString = searchString => {
407
+ if (!searchString) {
408
+ return 'invalid';
409
+ }
410
+ const searchParams = new URLSearchParams(searchString);
411
+ const value = searchParams.get('_pagination');
412
+ if (value === '' || value === null || value === '[]') {
413
+ return 'invalid';
414
+ }
415
+ const pagination = value.slice(1, value.length - 1).split(',');
416
+ const page = parseFloat(pagination[0]);
417
+ const pageSize = parseFloat(pagination[1]);
418
+ const direction = pagination[2];
419
+ if (!Number.isNaN(page) && !Number.isNaN(pageSize) && direction && ['next', 'back'].includes(direction)) {
420
+ return {
421
+ page,
422
+ pageSize,
423
+ direction: direction
10
424
  };
11
- /** Local Storage version, to upgrade when we want to force a clean out. */
12
- localStorageVersion?: number;
13
- /** Previous Local Storage versions to clean out when a new one is released. */
14
- previousLocalStorageVersions?: number[];
15
- }
425
+ }
426
+ return 'invalid';
427
+ };
428
+ const getSearchParamsFromPagination = pagination => {
429
+ const searchParams = new URLSearchParams();
430
+ searchParams.set('_pagination', `[${pagination.page},${pagination.pageSize},${pagination.direction}]`);
431
+ return searchParams;
432
+ };
433
+
434
+ // Rules:
435
+ // - if we have something in the URL, use that info
436
+ // - if we don't have that, use the localStorage and update the URL
437
+ // - if we don't have that, return an empty PaginationModel
438
+ const getPaginationModel = (search, localStoragePagination, setLocalStoragePagination, initialState, isNewVersion) => {
439
+ const defaultValue = initialState !== null && initialState !== void 0 && initialState.pagination ? _objectSpread2({
440
+ page: 0,
441
+ pageSize: 25,
442
+ direction: 'next'
443
+ }, initialState.pagination) : {
444
+ page: 0,
445
+ pageSize: 25,
446
+ direction: 'next'
447
+ };
448
+ if (isNewVersion) {
449
+ return defaultValue;
450
+ }
451
+ const pagination = getPaginationFromString(search);
452
+ if (pagination !== 'invalid') {
453
+ const searchFromPaginationModel = getSearchParamsFromPagination(pagination);
454
+ const searchString = urlSearchParamsToString(searchFromPaginationModel);
455
+ if (searchString !== localStoragePagination) {
456
+ setLocalStoragePagination(searchString);
457
+ }
458
+ return pagination;
459
+ }
460
+ const paginationModelFromLocalStorage = getPaginationFromString(localStoragePagination);
461
+ if (paginationModelFromLocalStorage !== 'invalid') {
462
+ return paginationModelFromLocalStorage;
463
+ }
464
+ return defaultValue;
465
+ };
466
+
467
+ /** COLUMN VISIBILITY */
468
+
469
+ const getSearchParamsFromColumnVisibility = (columnVisibility, columns) => {
470
+ const searchParams = new URLSearchParams();
471
+ const columnFields = columns.map(column => column.field);
472
+
473
+ // if column visibility model is empty, show all columns
474
+ if (Object.keys(columnVisibility).length == 0) {
475
+ searchParams.set('_columnVisibility', `[${columnFields.join(',')}]`);
476
+ return searchParams;
477
+ }
478
+ const finalColumnVisibility = columns.filter(c => {
479
+ var _c$hideable;
480
+ return !((_c$hideable = c === null || c === void 0 ? void 0 : c.hideable) !== null && _c$hideable !== void 0 ? _c$hideable : true);
481
+ }).map(c => c.field).reduce((acc, colName) => {
482
+ return _objectSpread2(_objectSpread2({}, acc), {}, {
483
+ [colName]: true
484
+ });
485
+ }, columnVisibility);
486
+ const visibleColumns = Object.entries(finalColumnVisibility)
487
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
488
+ .filter(_ref => {
489
+ let [_, visible] = _ref;
490
+ return visible;
491
+ })
492
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
493
+ .map(_ref2 => {
494
+ let [column, _] = _ref2;
495
+ return encodeValue(column);
496
+ });
497
+ searchParams.set('_columnVisibility', `[${visibleColumns.join(',')}]`);
498
+ return searchParams;
499
+ };
500
+ const getColumnVisibilityFromString = (notParsed, tableColumns) => {
501
+ if (!notParsed || notParsed.length === 1 && notParsed[0] === '?') {
502
+ return 'invalid';
503
+ }
504
+ // remove the initial ? if present
505
+ const parsed = notParsed[0] === '?' ? notParsed.slice(1) : notParsed;
506
+ const visibility = {};
507
+ let exist = false;
508
+ let visibleColumnsCount = 0;
509
+ for (const item of parsed.split('&')) {
510
+ // if it's not column visibility field, skip
511
+ const fieldURL = item.split('=')[0];
512
+ if (fieldURL !== '_columnVisibility') {
513
+ continue;
514
+ }
515
+ // e.g. item = _columnVisibility[abc,def]
516
+ const left = item.split(']')[0];
517
+ if (left.split('[').length < 2) {
518
+ continue;
519
+ }
520
+ const encodedValues = item.split('[')[1].split(']')[0];
521
+ if (typeof encodedValues !== 'string') {
522
+ continue;
523
+ }
524
+ exist = true;
525
+ const columnFields = tableColumns.map(column => column.field);
526
+ // TODO: Add validation that , is present
527
+ const columns = encodedValues.split(',').map(value => decodeValue(value));
528
+
529
+ // for each column, check if it's visible and add it to visibility model
530
+ for (const column of columnFields) {
531
+ const isColumnVisible = columns.includes(column);
532
+ visibility[column] = isColumnVisible;
533
+ if (isColumnVisible) {
534
+ visibleColumnsCount += 1;
535
+ }
536
+ }
537
+ }
538
+ if (visibleColumnsCount === 0 && !exist) {
539
+ return 'invalid';
540
+ }
541
+ return visibility;
542
+ };
543
+
544
+ // Rules:
545
+ // - if we have something in the URL, use that info
546
+ // - if we don't have that, use the localStorage and update the URL
547
+ // - if we don't have that, return an empty ColumnVisibilityModel (which is all columns)
548
+ // NOTE: the `defaultHidden` is a custom field and not standard DataGrid
549
+ // The reason is the following bug: https://github.com/mui/mui-x/issues/8407
550
+ const getColumnsVisibility = (search, columns, localStorageColumnsVisibility, setLocalStorageColumnsVisibility, initialState, isNewVersion) => {
551
+ var _initialState$columns3;
552
+ const defaultValue = {};
553
+ for (const column of columns) {
554
+ var _initialState$columns, _initialState$columns2;
555
+ const field = column.field;
556
+ if ((initialState === null || initialState === void 0 ? void 0 : (_initialState$columns = initialState.columns) === null || _initialState$columns === void 0 ? void 0 : (_initialState$columns2 = _initialState$columns.columnVisibilityModel) === null || _initialState$columns2 === void 0 ? void 0 : _initialState$columns2[field]) !== undefined) {
557
+ defaultValue[field] = initialState.columns.columnVisibilityModel[field];
558
+ } else {
559
+ defaultValue[field] = column.defaultHidden !== true; // undefined will be true
560
+ }
561
+ }
562
+
563
+ if (isNewVersion) {
564
+ return defaultValue;
565
+ }
566
+ const columnVisibility = getColumnVisibilityFromString(search, columns);
567
+ if (columnVisibility !== 'invalid') {
568
+ const searchColumnVisibility = getSearchParamsFromColumnVisibility(columnVisibility, columns);
569
+ if (searchColumnVisibility.toString() !== localStorageColumnsVisibility) {
570
+ setLocalStorageColumnsVisibility(searchColumnVisibility.toString());
571
+ }
572
+ return columnVisibility;
573
+ }
574
+ const columnVisibilityFromLocalStorage = getColumnVisibilityFromString(localStorageColumnsVisibility, columns);
575
+ if (columnVisibilityFromLocalStorage !== 'invalid') {
576
+ return columnVisibilityFromLocalStorage;
577
+ }
578
+ if (initialState !== null && initialState !== void 0 && (_initialState$columns3 = initialState.columns) !== null && _initialState$columns3 !== void 0 && _initialState$columns3.columnVisibilityModel) {
579
+ return initialState.columns.columnVisibilityModel;
580
+ }
581
+ return defaultValue;
582
+ };
583
+ const getPinnedColumnsFromString = (notParsed, tableColumns) => {
584
+ if (!notParsed || notParsed.length === 1 && notParsed[0] === '?') {
585
+ return 'invalid';
586
+ }
587
+ // remove the initial ? if present
588
+ const parsed = notParsed[0] === '?' ? notParsed.slice(1) : notParsed;
589
+ const pinnedColumns = {};
590
+ for (const item of parsed.split('&')) {
591
+ const fieldURL = item.split('=')[0];
592
+ if (fieldURL !== '_pinnedColumnsLeft' && fieldURL !== '_pinnedColumnsRight') {
593
+ continue;
594
+ }
595
+ const left = item.split(']')[0];
596
+ if (left.split('[').length < 2) {
597
+ continue;
598
+ }
599
+ const encodedValues = item.split('[')[1].split(']')[0];
600
+ if (typeof encodedValues !== 'string') {
601
+ continue;
602
+ }
603
+ const columnFields = [...tableColumns.map(column => column.field), '__check__'];
604
+ const columns = encodedValues.split(',').map(value => decodeValue(value)).filter(val => typeof val === 'string' && columnFields.includes(val));
605
+ if (fieldURL === '_pinnedColumnsLeft') {
606
+ pinnedColumns['left'] = columns;
607
+ }
608
+ if (fieldURL === '_pinnedColumnsRight') {
609
+ pinnedColumns['right'] = columns;
610
+ }
611
+ }
612
+ return pinnedColumns['left'] || pinnedColumns['right'] ? {
613
+ left: pinnedColumns['left'] || [],
614
+ right: pinnedColumns['right'] || []
615
+ } : 'invalid';
616
+ };
617
+ const getSearchParamsFromPinnedColumns = pinnedColumns => {
618
+ var _pinnedColumns$left, _pinnedColumns$right;
619
+ const searchParams = new URLSearchParams();
620
+ const pinnedColumnLeft = ((_pinnedColumns$left = pinnedColumns.left) === null || _pinnedColumns$left === void 0 ? void 0 : _pinnedColumns$left.map(val => encodeValue(val))) || [];
621
+ const pinnedColumnRight = ((_pinnedColumns$right = pinnedColumns.right) === null || _pinnedColumns$right === void 0 ? void 0 : _pinnedColumns$right.map(val => encodeValue(val))) || [];
622
+ searchParams.set('_pinnedColumnsLeft', `[${pinnedColumnLeft.join(',')}]`);
623
+ searchParams.set('_pinnedColumnsRight', `[${pinnedColumnRight.join(',')}]`);
624
+ return searchParams;
625
+ };
626
+
627
+ // Rules:
628
+ // - if we have something in the URL, use that info
629
+ // - if we don't have that, use the localStorage and update the URL
630
+ // - if we don't have that, return an empty ColumnVisibilityModel (which is all columns)
631
+ const getPinnedColumns = (search, columns, localStoragePinnedColumns, setLocalStoragePinnedColumns, initialState, isNewVersion) => {
632
+ const defaultValue = initialState !== null && initialState !== void 0 && initialState.pinnedColumns ? {
633
+ left: (initialState === null || initialState === void 0 ? void 0 : initialState.pinnedColumns['left']) || [],
634
+ right: (initialState === null || initialState === void 0 ? void 0 : initialState.pinnedColumns['right']) || []
635
+ } : {
636
+ left: [],
637
+ right: []
638
+ };
639
+ if (isNewVersion) {
640
+ return defaultValue;
641
+ }
642
+ const pinnedColumns = getPinnedColumnsFromString(search, columns);
643
+ if (pinnedColumns !== 'invalid') {
644
+ const searchPinnedColumns = getSearchParamsFromPinnedColumns(pinnedColumns);
645
+ if (searchPinnedColumns.toString() !== localStoragePinnedColumns) {
646
+ setLocalStoragePinnedColumns(searchPinnedColumns.toString());
647
+ }
648
+ return pinnedColumns;
649
+ }
650
+ const pinnedColumnsFromLocalStorage = getPinnedColumnsFromString(localStoragePinnedColumns, columns);
651
+ if (pinnedColumnsFromLocalStorage !== 'invalid') {
652
+ return pinnedColumnsFromLocalStorage;
653
+ }
654
+ return defaultValue;
655
+ };
656
+ const getSearchParamsFromTab = search => {
657
+ const searchParams = new URLSearchParams();
658
+ const openTab = new URLSearchParams(search).get('tab');
659
+ if (openTab) {
660
+ searchParams.set('tab', openTab);
661
+ }
662
+ return searchParams;
663
+ };
664
+ const getFinalSearch = _ref3 => {
665
+ let {
666
+ search,
667
+ localStorageVersion,
668
+ filterModel,
669
+ sortModel,
670
+ paginationModel,
671
+ columnsVisibilityModel,
672
+ pinnedColumnsModel,
673
+ columns
674
+ } = _ref3;
675
+ const filterModelSearch = getSearchParamsFromFilterModel(filterModel);
676
+ const sortModelSearch = getSearchParamsFromSorting(sortModel);
677
+ const paginationModelSearch = getSearchParamsFromPagination(paginationModel);
678
+ const columnVisibilityModelSearch = getSearchParamsFromColumnVisibility(columnsVisibilityModel, columns);
679
+ const pinnedColumnsModelSearch = getSearchParamsFromPinnedColumns(pinnedColumnsModel);
680
+ const tabSearch = getSearchParamsFromTab(search);
681
+ const searchParams = new URLSearchParams();
682
+ for (const [key, value] of new URLSearchParams(search)) {
683
+ if (!key.startsWith('_')) {
684
+ searchParams.set(key, value);
685
+ }
686
+ }
687
+ searchParams.set('v', `${localStorageVersion}`);
688
+
689
+ // Add quickFilterValues explicitly if present in filterModel
690
+ if (filterModel.quickFilterValues && filterModel.quickFilterValues.length > 0) {
691
+ // Encode array as JSON string to preserve all values in one param
692
+ searchParams.set('_quickFilterValues', encodeURIComponent(JSON.stringify(filterModel.quickFilterValues)));
693
+ }
694
+ return new URLSearchParams([...searchParams, ...filterModelSearch, ...sortModelSearch, ...paginationModelSearch, ...tabSearch, ...pinnedColumnsModelSearch, ...columnVisibilityModelSearch]);
695
+ };
696
+ /** Return the state of the table given the URL and the local storage state */
697
+ const getModelsParsedOrUpdateLocalStorage = (search, localStorageVersion, columns, historyReplace, initialState, localStorage) => {
698
+ const currentVersion = new URLSearchParams(search).get('v');
699
+ const isNewVersion = !currentVersion || Number(currentVersion) !== localStorageVersion;
700
+ const {
701
+ localStorageFilters,
702
+ setLocalStorageFilters,
703
+ localStorageSorting,
704
+ setLocalStorageSorting,
705
+ localStoragePagination,
706
+ setLocalStoragePagination,
707
+ localStorageColumnsVisibility,
708
+ setLocalStorageColumnsVisibility,
709
+ localStoragePinnedColumns,
710
+ setLocalStoragePinnedColumns
711
+ } = localStorage;
712
+ const filterModel = getFilterModel(search, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion);
713
+ const sortModel = getSortModel(search, columns, localStorageSorting, setLocalStorageSorting, initialState, isNewVersion);
714
+ const paginationModel = getPaginationModel(search, localStoragePagination, setLocalStoragePagination, initialState, isNewVersion);
715
+ const columnVisibilityModel = getColumnsVisibility(search, columns, localStorageColumnsVisibility, setLocalStorageColumnsVisibility, initialState, isNewVersion);
716
+ const pinnedColumnsModel = getPinnedColumns(search, columns, localStoragePinnedColumns, setLocalStoragePinnedColumns, initialState, isNewVersion);
717
+ const finalSearch = getFinalSearch({
718
+ localStorageVersion,
719
+ search,
720
+ filterModel,
721
+ sortModel,
722
+ paginationModel,
723
+ columnsVisibilityModel: columnVisibilityModel,
724
+ pinnedColumnsModel,
725
+ columns
726
+ });
727
+ const searchString = urlSearchParamsToString(finalSearch);
728
+ if (searchString !== search) {
729
+ historyReplace(searchString);
730
+ }
731
+ return {
732
+ filterModel,
733
+ sortModel,
734
+ paginationModel,
735
+ columnVisibilityModel,
736
+ pinnedColumnsModel
737
+ };
738
+ };
739
+ const updateUrl = (_ref4, search, localStorageVersion, historyReplace, columns) => {
740
+ let {
741
+ filterModel,
742
+ sortModel,
743
+ paginationModel,
744
+ columnsModel: columnsVisibilityModel,
745
+ pinnedColumnsModel
746
+ } = _ref4;
747
+ const newSearch = getFinalSearch({
748
+ search,
749
+ localStorageVersion,
750
+ filterModel,
751
+ sortModel,
752
+ paginationModel,
753
+ columnsVisibilityModel,
754
+ pinnedColumnsModel,
755
+ columns
756
+ });
757
+ const searchString = urlSearchParamsToString(newSearch);
758
+ if (searchString !== search) {
759
+ historyReplace(searchString);
760
+ }
761
+ };
762
+
763
+ // Note: this is a comparator to sort the filters, not pure comparison
764
+ // do not use it for equivalence (e.g. with value `3` and undefined we
765
+ // will get 0).
766
+ const compareFilters = (firstFilter, secondFilter) => {
767
+ if (firstFilter.columnField < secondFilter.columnField) {
768
+ return -1;
769
+ } else if (firstFilter.columnField > secondFilter.columnField) {
770
+ return 1;
771
+ }
772
+ if (firstFilter.operatorValue === undefined || secondFilter.operatorValue === undefined) {
773
+ return 0;
774
+ }
775
+ if (firstFilter.operatorValue < secondFilter.operatorValue) {
776
+ return -1;
777
+ } else if (firstFilter.operatorValue > secondFilter.operatorValue) {
778
+ return 1;
779
+ }
780
+ if (firstFilter.value < secondFilter.value) {
781
+ return -1;
782
+ } else if (firstFilter.value > secondFilter.value) {
783
+ return 1;
784
+ }
785
+ return 0;
786
+ };
787
+ const areFiltersEquivalent = (firstFilter, secondFilter) => {
788
+ return firstFilter.columnField === secondFilter.columnField && firstFilter.operatorValue === secondFilter.operatorValue && firstFilter.value === secondFilter.value;
789
+ };
790
+ const areFilterModelsEquivalent = (filterModel, filterModelToMatch) => {
791
+ const {
792
+ items,
793
+ linkOperator
794
+ } = filterModel;
795
+ const {
796
+ items: itemsToMatch,
797
+ linkOperator: linkOperatorToMatch
798
+ } = filterModelToMatch;
799
+ if (linkOperator !== linkOperatorToMatch) {
800
+ return false;
801
+ }
802
+ if (items.length !== itemsToMatch.length) {
803
+ return false;
804
+ }
805
+ items.sort(compareFilters);
806
+ itemsToMatch.sort(compareFilters);
807
+ for (let i = 0; i < items.length; i++) {
808
+ const filter = items[i];
809
+ const filterToCompare = itemsToMatch[i];
810
+
811
+ // compareFilters return 0 if and only if the filters have the same
812
+ // columnField, operatorValue, and value
813
+ if (!areFiltersEquivalent(filter, filterToCompare)) {
814
+ return false;
815
+ }
816
+ }
817
+ return true;
818
+ };
819
+
820
+ // Get and Set data from LocalStorage WITHOUT useState
821
+
822
+ // triggering a state update and consecutive re-render
823
+ const useFetchState = (defaultValue, key) => {
824
+ let stickyValue = null;
825
+ try {
826
+ stickyValue = window.localStorage.getItem(key);
827
+ } catch (e) {
828
+ console.error('StatefulDataGrid: error getting item from local storage: ', e);
829
+ }
830
+ let parsedValue = stickyValue !== null && stickyValue !== undefined && stickyValue !== 'undefined' ? JSON.parse(stickyValue) : defaultValue;
831
+
832
+ // TODO: temporary workaround to avoid clashes when someone had sorting on the now-removed screenshot field (renamed to num_annotations)
833
+ // Consider upgrading the Datagrid component library as the exception handling was added in this PR: https://github.com/mui-org/material-ui-x/pull/3224
834
+ if (parsedValue instanceof Array) {
835
+ const fields = (parsedValue || []).map(item => item.field);
836
+ if (fields.includes('screenshot') || fields.includes('diffs')) {
837
+ parsedValue = defaultValue;
838
+ }
839
+ }
840
+ const updateValue = useCallback(value => {
841
+ try {
842
+ window.localStorage.setItem(key, JSON.stringify(value));
843
+ } catch (e) {
844
+ console.error('StatefulDataGrid: error setting item into local storage: ', e);
845
+ }
846
+ }, [key]);
847
+ return [parsedValue, updateValue];
848
+ };
849
+
850
+ const useTableStates = (id, version) => {
851
+ const [paginationModel, setPaginationModel] = useFetchState('', buildStorageKey({
852
+ id,
853
+ version,
854
+ category: PAGINATION_MODEL_KEY
855
+ }));
856
+ const [sortModel, setSortModel] = useFetchState('', buildStorageKey({
857
+ id,
858
+ version,
859
+ category: SORT_MODEL_KEY
860
+ }));
861
+ const [localStorageFilters, setLocalStorageFilters] = useFetchState('', buildStorageKey({
862
+ id,
863
+ version,
864
+ category: FILTER_SEARCH_KEY
865
+ }));
866
+ const [visibilityModelLocalStorage, setVisibilityModelLocalStorage] = useFetchState('', buildStorageKey({
867
+ id,
868
+ version,
869
+ category: VISIBILITY_MODEL_KEY
870
+ }));
871
+ const [pinnedColumns, setPinnedColumns] = useFetchState('_pinnedColumnsLeft=[]&_pinnedColumnsRight=[]', buildStorageKey({
872
+ id,
873
+ version,
874
+ category: PINNED_COLUMNS
875
+ }));
876
+ const [dimensionModel, setDimensionModel] = useFetchState({}, buildStorageKey({
877
+ id,
878
+ version,
879
+ category: DIMENSION_MODEL_KEY
880
+ }));
881
+ return {
882
+ paginationModel,
883
+ setPaginationModel,
884
+ sortModel,
885
+ setSortModel,
886
+ localStorageFilters,
887
+ setLocalStorageFilters,
888
+ visibilityModelLocalStorage,
889
+ setVisibilityModelLocalStorage,
890
+ pinnedColumns,
891
+ setPinnedColumns,
892
+ dimensionModel,
893
+ setDimensionModel
894
+ };
895
+ };
896
+
897
+ const useStatefulTable = props => {
898
+ const {
899
+ // density = 'standard',
900
+ apiRef,
901
+ initialState,
902
+ columns: propsColumns,
903
+ onColumnVisibilityModelChange: propsOnColumnVisibilityModelChange,
904
+ onColumnWidthChange: propsOnColumnWidthChange,
905
+ onFilterModelChange: propsOnFilterModelChange,
906
+ onPageChange: propsOnPageChange,
907
+ onPageSizeChange: propsOnPageSizeChange,
908
+ onPinnedColumnsChange: propsOnPinnedColumnsChange,
909
+ onSortModelChange: propsOnSortModelChange,
910
+ useRouter,
911
+ localStorageVersion = 1,
912
+ previousLocalStorageVersions = []
913
+ } = props;
914
+ const {
915
+ search,
916
+ pathname,
917
+ historyReplace
918
+ } = useRouter();
919
+ const id = pathname;
920
+
921
+ // States and setters persisted in the local storage for this table
922
+ const {
923
+ paginationModel,
924
+ setPaginationModel,
925
+ sortModel,
926
+ setSortModel,
927
+ localStorageFilters,
928
+ setLocalStorageFilters,
929
+ visibilityModelLocalStorage,
930
+ setVisibilityModelLocalStorage,
931
+ pinnedColumns,
932
+ setPinnedColumns,
933
+ dimensionModel,
934
+ setDimensionModel
935
+ } = useTableStates(id, localStorageVersion);
936
+
937
+ // clearing up old version keys
938
+ useEffect(() => clearPreviousVersionStorage(id, previousLocalStorageVersions), [id, previousLocalStorageVersions]);
939
+ const onColumnDimensionChange = useCallback(_ref => {
940
+ let {
941
+ newWidth,
942
+ field
943
+ } = _ref;
944
+ setDimensionModel(_objectSpread2(_objectSpread2({}, dimensionModel), {}, {
945
+ [field]: newWidth
946
+ }));
947
+ }, [dimensionModel, setDimensionModel]);
948
+ const {
949
+ filterModel: filterParsed,
950
+ sortModel: sortModelParsed,
951
+ paginationModel: paginationModelParsed,
952
+ columnVisibilityModel: visibilityModel,
953
+ pinnedColumnsModel
954
+ } = getModelsParsedOrUpdateLocalStorage(search || '', localStorageVersion, propsColumns, historyReplace, initialState, {
955
+ localStorageFilters,
956
+ setLocalStorageFilters,
957
+ localStorageSorting: sortModel,
958
+ setLocalStorageSorting: setSortModel,
959
+ localStoragePagination: paginationModel,
960
+ setLocalStoragePagination: setPaginationModel,
961
+ localStorageColumnsVisibility: visibilityModelLocalStorage,
962
+ setLocalStorageColumnsVisibility: setVisibilityModelLocalStorage,
963
+ localStoragePinnedColumns: pinnedColumns,
964
+ setLocalStoragePinnedColumns: setPinnedColumns
965
+ });
966
+ const columns = useMemo(() => propsColumns.map(column => {
967
+ column.width = dimensionModel[column.field] || column.width || 100;
968
+ return column;
969
+ }), [propsColumns, dimensionModel]);
970
+
971
+ /** Add resetPage method to apiRef. */
972
+ apiRef.current.resetPage = () => {
973
+ apiRef.current.setPage(0);
974
+ };
975
+ return {
976
+ apiRef,
977
+ columns,
978
+ onFilterModelChange: (model, details) => {
979
+ const filterModel = _objectSpread2(_objectSpread2({}, model), {}, {
980
+ items: model.items.map(item => {
981
+ const column = apiRef.current.getColumn(item.columnField);
982
+ item.type = column.type || 'string';
983
+ return item;
984
+ }),
985
+ quickFilterValues: model.quickFilterValues || []
986
+ });
987
+ propsOnFilterModelChange === null || propsOnFilterModelChange === void 0 ? void 0 : propsOnFilterModelChange(filterModel, details);
988
+ updateUrl({
989
+ filterModel: filterModel,
990
+ sortModel: sortModelParsed,
991
+ paginationModel: paginationModelParsed,
992
+ columnsModel: apiRef.current.state.columns.columnVisibilityModel,
993
+ pinnedColumnsModel: pinnedColumnsModel
994
+ }, search, localStorageVersion, historyReplace, columns);
995
+ },
996
+ filterModel: filterParsed,
997
+ onSortModelChange: (model, details) => {
998
+ propsOnSortModelChange === null || propsOnSortModelChange === void 0 ? void 0 : propsOnSortModelChange(model, details);
999
+ updateUrl({
1000
+ filterModel: filterParsed,
1001
+ sortModel: model,
1002
+ paginationModel: paginationModelParsed,
1003
+ columnsModel: apiRef.current.state.columns.columnVisibilityModel,
1004
+ pinnedColumnsModel: pinnedColumnsModel
1005
+ }, search, localStorageVersion, historyReplace, columns);
1006
+ },
1007
+ sortModel: sortModelParsed,
1008
+ onPinnedColumnsChange: (pinnedColumns, details) => {
1009
+ propsOnPinnedColumnsChange === null || propsOnPinnedColumnsChange === void 0 ? void 0 : propsOnPinnedColumnsChange(pinnedColumns, details);
1010
+ updateUrl({
1011
+ filterModel: filterParsed,
1012
+ sortModel: sortModelParsed,
1013
+ paginationModel: paginationModelParsed,
1014
+ columnsModel: apiRef.current.state.columns.columnVisibilityModel,
1015
+ pinnedColumnsModel: pinnedColumns
1016
+ }, search, localStorageVersion, historyReplace, columns);
1017
+ },
1018
+ pinnedColumns: pinnedColumnsModel,
1019
+ page: paginationModelParsed.page,
1020
+ pageSize: paginationModelParsed.pageSize,
1021
+ onPageChange: (page, details) => {
1022
+ const direction = paginationModelParsed.page < page ? 'next' : 'back';
1023
+ propsOnPageChange === null || propsOnPageChange === void 0 ? void 0 : propsOnPageChange(page, details);
1024
+ updateUrl({
1025
+ filterModel: filterParsed,
1026
+ sortModel: sortModelParsed,
1027
+ paginationModel: {
1028
+ page,
1029
+ pageSize: paginationModelParsed.pageSize,
1030
+ direction
1031
+ },
1032
+ columnsModel: apiRef.current.state.columns.columnVisibilityModel,
1033
+ pinnedColumnsModel: pinnedColumnsModel
1034
+ }, search, localStorageVersion, historyReplace, columns);
1035
+ },
1036
+ onPageSizeChange: (pageSize, details) => {
1037
+ propsOnPageSizeChange === null || propsOnPageSizeChange === void 0 ? void 0 : propsOnPageSizeChange(pageSize, details);
1038
+ updateUrl({
1039
+ filterModel: filterParsed,
1040
+ sortModel: sortModelParsed,
1041
+ paginationModel: {
1042
+ page: paginationModelParsed.page,
1043
+ pageSize,
1044
+ direction: paginationModelParsed.direction
1045
+ },
1046
+ columnsModel: apiRef.current.state.columns.columnVisibilityModel,
1047
+ pinnedColumnsModel: pinnedColumnsModel
1048
+ }, search, localStorageVersion, historyReplace, columns);
1049
+ },
1050
+ columnVisibilityModel: visibilityModel,
1051
+ onColumnVisibilityModelChange: (columnsVisibilityModel, details) => {
1052
+ propsOnColumnVisibilityModelChange === null || propsOnColumnVisibilityModelChange === void 0 ? void 0 : propsOnColumnVisibilityModelChange(columnsVisibilityModel, details);
1053
+ updateUrl({
1054
+ filterModel: filterParsed,
1055
+ sortModel: sortModelParsed,
1056
+ paginationModel: paginationModelParsed,
1057
+ columnsModel: columnsVisibilityModel,
1058
+ pinnedColumnsModel: pinnedColumnsModel
1059
+ }, search, localStorageVersion, historyReplace, columns);
1060
+ },
1061
+ onColumnWidthChange: (params, event, details) => {
1062
+ propsOnColumnWidthChange === null || propsOnColumnWidthChange === void 0 ? void 0 : propsOnColumnWidthChange(params, event, details);
1063
+ onColumnDimensionChange({
1064
+ newWidth: params.width,
1065
+ field: params.colDef.field
1066
+ });
1067
+ }
1068
+ };
1069
+ };
1070
+
1071
+ const _excluded = ["apiRef", "autoHeight", "className", "columns", "columnTypes", "components", "componentsProps", "filterModel", "columnVisibilityModel", "pinnedColumns", "sortModel", "page", "pageSize", "height", "hideToolbar", "initialState", "isRowSelectable", "license", "localStorageVersion", "previousLocalStorageVersions", "onFilterModelChange", "selectionModel", "onColumnWidthChange", "onPageChange", "onPageSizeChange", "onSelectionModelChange", "onColumnVisibilityModelChange", "onPinnedColumnsChange", "onSortModelChange", "pagination", "paginationPlacement", "paginationProps", "rows", "rowsPerPageOptions", "sx", "theme", "useRouter", "paginationMode", "rowCount"];
1072
+ const COMPONENT_NAME = 'DataGrid';
1073
+ const CLASSNAME = 'redsift-datagrid';
1074
+ const StatefulDataGrid = /*#__PURE__*/forwardRef((props, ref) => {
1075
+ const datagridRef = ref || useRef();
1076
+ const {
1077
+ apiRef: propsApiRef,
1078
+ autoHeight,
1079
+ className,
1080
+ columns,
1081
+ columnTypes: propsColumnTypes,
1082
+ components,
1083
+ componentsProps,
1084
+ filterModel: propsFilterModel,
1085
+ columnVisibilityModel: propsColumnVisibilityModel,
1086
+ pinnedColumns: propsPinnedColumns,
1087
+ sortModel: propsSortModel,
1088
+ page: propsPage,
1089
+ pageSize: propsPageSize,
1090
+ height: propsHeight,
1091
+ hideToolbar,
1092
+ initialState,
1093
+ isRowSelectable,
1094
+ license = process.env.MUI_LICENSE_KEY,
1095
+ localStorageVersion,
1096
+ previousLocalStorageVersions,
1097
+ onFilterModelChange: propsOnFilterModelChange,
1098
+ selectionModel: propsSelectionModel,
1099
+ onColumnWidthChange: propsOnColumnWidthChange,
1100
+ onPageChange: propsOnPageChange,
1101
+ onPageSizeChange: propsOnPageSizeChange,
1102
+ onSelectionModelChange: propsOnSelectionModelChange,
1103
+ onColumnVisibilityModelChange: propsOnColumnVisibilityModelChange,
1104
+ onPinnedColumnsChange: propsOnPinnedColumnsChange,
1105
+ onSortModelChange: propsOnSortModelChange,
1106
+ pagination,
1107
+ paginationPlacement = 'both',
1108
+ paginationProps,
1109
+ rows,
1110
+ rowsPerPageOptions,
1111
+ sx,
1112
+ theme: propsTheme,
1113
+ useRouter,
1114
+ paginationMode = 'client',
1115
+ rowCount
1116
+ } = props,
1117
+ forwardedProps = _objectWithoutProperties(props, _excluded);
1118
+ const theme = useTheme(propsTheme);
1119
+ const _apiRef = useGridApiRef();
1120
+ const apiRef = propsApiRef !== null && propsApiRef !== void 0 ? propsApiRef : _apiRef;
1121
+ const RenderedToolbar = components !== null && components !== void 0 && components.Toolbar ? components.Toolbar : Toolbar;
1122
+ LicenseInfo.setLicenseKey(license);
1123
+ const height = propsHeight !== null && propsHeight !== void 0 ? propsHeight : autoHeight ? undefined : '500px';
1124
+ const {
1125
+ onColumnVisibilityModelChange: controlledOnColumnVisibilityModelChange,
1126
+ onFilterModelChange: controlledOnFilterModelChange,
1127
+ onPageChange: controlledOnPageChange,
1128
+ onPageSizeChange: controlledOnPageSizeChange,
1129
+ onPinnedColumnsChange: controlledOnPinnedColumnsChange,
1130
+ onSortModelChange: controlledOnSortModelChange
1131
+ } = useControlledDatagridState({
1132
+ initialState,
1133
+ rowsPerPageOptions,
1134
+ propsColumnVisibilityModel,
1135
+ propsFilterModel,
1136
+ propsOnColumnVisibilityModelChange,
1137
+ propsOnFilterModelChange,
1138
+ propsOnPinnedColumnsChange,
1139
+ propsOnSortModelChange,
1140
+ propsPage,
1141
+ propsPageSize,
1142
+ propsPinnedColumns,
1143
+ propsSortModel,
1144
+ propsOnPageChange,
1145
+ propsOnPageSizeChange
1146
+ });
1147
+ const {
1148
+ columnVisibilityModel,
1149
+ filterModel,
1150
+ onColumnVisibilityModelChange,
1151
+ onFilterModelChange,
1152
+ onPageChange,
1153
+ onPageSizeChange,
1154
+ onPinnedColumnsChange,
1155
+ onSortModelChange,
1156
+ page,
1157
+ pageSize,
1158
+ pinnedColumns,
1159
+ sortModel,
1160
+ onColumnWidthChange
1161
+ } = useStatefulTable({
1162
+ apiRef: apiRef,
1163
+ initialState,
1164
+ columns,
1165
+ onColumnVisibilityModelChange: controlledOnColumnVisibilityModelChange,
1166
+ onColumnWidthChange: propsOnColumnWidthChange,
1167
+ onFilterModelChange: controlledOnFilterModelChange,
1168
+ onPageChange: controlledOnPageChange,
1169
+ onPageSizeChange: controlledOnPageSizeChange,
1170
+ onPinnedColumnsChange: controlledOnPinnedColumnsChange,
1171
+ onSortModelChange: controlledOnSortModelChange,
1172
+ useRouter: useRouter,
1173
+ localStorageVersion,
1174
+ previousLocalStorageVersions
1175
+ });
1176
+ const [selectionModel, setSelectionModel] = useState(propsSelectionModel !== null && propsSelectionModel !== void 0 ? propsSelectionModel : []);
1177
+ useEffect(() => {
1178
+ setSelectionModel(propsSelectionModel !== null && propsSelectionModel !== void 0 ? propsSelectionModel : []);
1179
+ }, [propsSelectionModel]);
1180
+ const onSelectionModelChange = (selectionModel, details) => {
1181
+ if (propsOnSelectionModelChange) {
1182
+ propsOnSelectionModelChange(selectionModel, details);
1183
+ } else {
1184
+ setSelectionModel(selectionModel);
1185
+ }
1186
+ };
1187
+ const selectionStatus = useRef({
1188
+ type: 'none',
1189
+ numberOfSelectedRows: 0,
1190
+ numberOfSelectedRowsInPage: 0,
1191
+ page,
1192
+ pageSize: pageSize
1193
+ });
16
1194
 
17
- declare const StatefulDataGrid: Comp<StatefulDataGridProps, HTMLDivElement>;
1195
+ // in server-side pagination we want to update the selection status
1196
+ // every time we navigate between pages, resize our page or select something
1197
+ useEffect(() => {
1198
+ if (paginationMode == 'server') {
1199
+ onServerSideSelectionStatusChange(Array.isArray(selectionModel) ? selectionModel : [selectionModel], apiRef, selectionStatus, isRowSelectable, page, pageSize);
1200
+ }
1201
+ }, [selectionModel, page, pageSize]);
1202
+ if (!Array.isArray(rows)) {
1203
+ return null;
1204
+ }
1205
+ const muiTheme = useMemo(() => createTheme({
1206
+ palette: {
1207
+ mode: theme,
1208
+ primary: {
1209
+ main: RedsiftColorBlueN
1210
+ },
1211
+ background: {
1212
+ default: theme === 'dark' ? RedsiftColorNeutralXDarkGrey : RedsiftColorNeutralWhite,
1213
+ paper: theme === 'dark' ? RedsiftColorNeutralXDarkGrey : RedsiftColorNeutralWhite
1214
+ }
1215
+ }
1216
+ }), [theme]);
1217
+ return /*#__PURE__*/React__default.createElement(ThemeProvider, {
1218
+ value: {
1219
+ theme
1220
+ }
1221
+ }, /*#__PURE__*/React__default.createElement(ThemeProvider$1, {
1222
+ theme: muiTheme
1223
+ }, /*#__PURE__*/React__default.createElement(StyledDataGrid, {
1224
+ ref: datagridRef,
1225
+ className: classNames(StatefulDataGrid.className, className),
1226
+ $height: height
1227
+ }, /*#__PURE__*/React__default.createElement(DataGridPro, _extends({}, forwardedProps, {
1228
+ apiRef: apiRef,
1229
+ columns: columns,
1230
+ columnVisibilityModel: columnVisibilityModel,
1231
+ filterModel: filterModel,
1232
+ onColumnVisibilityModelChange: onColumnVisibilityModelChange,
1233
+ onFilterModelChange: onFilterModelChange,
1234
+ onPageChange: onPageChange,
1235
+ onPageSizeChange: onPageSizeChange,
1236
+ onPinnedColumnsChange: onPinnedColumnsChange,
1237
+ onSortModelChange: onSortModelChange,
1238
+ page: page,
1239
+ pageSize: pageSize,
1240
+ pinnedColumns: pinnedColumns,
1241
+ sortModel: sortModel,
1242
+ rowsPerPageOptions: rowsPerPageOptions,
1243
+ onColumnWidthChange: onColumnWidthChange,
1244
+ initialState: initialState,
1245
+ isRowSelectable: isRowSelectable,
1246
+ pagination: pagination,
1247
+ paginationMode: paginationMode,
1248
+ keepNonExistentRowsSelected: paginationMode == 'server',
1249
+ rows: rows,
1250
+ rowCount: rowCount,
1251
+ autoHeight: autoHeight,
1252
+ checkboxSelectionVisibleOnly: Boolean(pagination),
1253
+ columnTypes: _objectSpread2(_objectSpread2({}, customColumnTypes), propsColumnTypes),
1254
+ components: _objectSpread2(_objectSpread2({
1255
+ BaseButton,
1256
+ BaseCheckbox,
1257
+ // BaseTextField,
1258
+ BasePopper,
1259
+ ColumnFilteredIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1260
+ displayName: "ColumnFilteredIcon"
1261
+ })),
1262
+ ColumnSelectorIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1263
+ displayName: "ColumnSelectorIcon"
1264
+ })),
1265
+ ColumnSortedAscendingIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1266
+ displayName: "ColumnSortedAscendingIcon"
1267
+ })),
1268
+ ColumnSortedDescendingIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1269
+ displayName: "ColumnSortedDescendingIcon"
1270
+ })),
1271
+ DensityCompactIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1272
+ displayName: "DensityCompactIcon"
1273
+ })),
1274
+ DensityStandardIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1275
+ displayName: "DensityStandardIcon"
1276
+ })),
1277
+ DensityComfortableIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1278
+ displayName: "DensityComfortableIcon"
1279
+ })),
1280
+ DetailPanelCollapseIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1281
+ displayName: "DetailPanelCollapseIcon"
1282
+ })),
1283
+ DetailPanelExpandIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1284
+ displayName: "DetailPanelExpandIcon"
1285
+ })),
1286
+ ExportIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({}, props, {
1287
+ displayName: "ExportIcon"
1288
+ })),
1289
+ OpenFilterButtonIcon: props => /*#__PURE__*/React__default.createElement(BaseIcon, _extends({
1290
+ displayName: "OpenFilterButtonIcon"
1291
+ }, props))
1292
+ }, components), {}, {
1293
+ Toolbar: ToolbarWrapper,
1294
+ Pagination: props => {
1295
+ return pagination ? paginationMode == 'server' ? /*#__PURE__*/React__default.createElement(ServerSideControlledPagination, _extends({}, props, {
1296
+ displaySelection: false,
1297
+ displayRowsPerPage: ['bottom', 'both'].includes(paginationPlacement),
1298
+ displayPagination: ['bottom', 'both'].includes(paginationPlacement),
1299
+ selectionStatus: selectionStatus.current,
1300
+ page: page,
1301
+ pageSize: pageSize,
1302
+ onPageChange: onPageChange,
1303
+ onPageSizeChange: onPageSizeChange,
1304
+ rowsPerPageOptions: rowsPerPageOptions,
1305
+ paginationProps: paginationProps,
1306
+ paginationMode: paginationMode,
1307
+ rowCount: rowCount
1308
+ })) : /*#__PURE__*/React__default.createElement(ControlledPagination, _extends({}, props, {
1309
+ displaySelection: false,
1310
+ displayRowsPerPage: ['bottom', 'both'].includes(paginationPlacement),
1311
+ displayPagination: ['bottom', 'both'].includes(paginationPlacement),
1312
+ selectionStatus: selectionStatus.current,
1313
+ apiRef: apiRef,
1314
+ isRowSelectable: isRowSelectable,
1315
+ page: page,
1316
+ pageSize: pageSize,
1317
+ onPageChange: onPageChange,
1318
+ onPageSizeChange: onPageSizeChange,
1319
+ rowsPerPageOptions: rowsPerPageOptions,
1320
+ paginationProps: paginationProps,
1321
+ paginationMode: paginationMode
1322
+ })) : null;
1323
+ }
1324
+ }),
1325
+ componentsProps: _objectSpread2(_objectSpread2({}, componentsProps), {}, {
1326
+ toolbar: _objectSpread2({
1327
+ hideToolbar,
1328
+ RenderedToolbar,
1329
+ filterModel,
1330
+ onFilterModelChange,
1331
+ pagination,
1332
+ paginationPlacement,
1333
+ selectionStatus,
1334
+ apiRef,
1335
+ isRowSelectable,
1336
+ page,
1337
+ pageSize,
1338
+ onPageChange,
1339
+ onPageSizeChange,
1340
+ rowsPerPageOptions,
1341
+ paginationProps,
1342
+ paginationMode,
1343
+ rowCount
1344
+ }, componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps.toolbar)
1345
+ }),
1346
+ selectionModel: selectionModel,
1347
+ onSelectionModelChange: (newSelectionModel, details) => {
1348
+ if (pagination && paginationMode != 'server') {
1349
+ const selectableRowsInPage = isRowSelectable ? gridPaginatedVisibleSortedGridRowEntriesSelector(apiRef).filter(_ref => {
1350
+ let {
1351
+ model
1352
+ } = _ref;
1353
+ return isRowSelectable({
1354
+ row: model
1355
+ });
1356
+ }).map(_ref2 => {
1357
+ let {
1358
+ id
1359
+ } = _ref2;
1360
+ return id;
1361
+ }) : gridPaginatedVisibleSortedGridRowIdsSelector(apiRef);
1362
+ const numberOfSelectableRowsInPage = selectableRowsInPage.length;
1363
+ const selectableRowsInTable = isRowSelectable ? gridFilteredSortedRowEntriesSelector(apiRef).filter(_ref3 => {
1364
+ let {
1365
+ model
1366
+ } = _ref3;
1367
+ return isRowSelectable({
1368
+ row: model
1369
+ });
1370
+ }).map(_ref4 => {
1371
+ let {
1372
+ id
1373
+ } = _ref4;
1374
+ return id;
1375
+ }) : gridFilteredSortedRowIdsSelector(apiRef);
1376
+ const numberOfSelectableRowsInTable = selectableRowsInTable.length;
1377
+ const numberOfSelectedRows = newSelectionModel.length;
1378
+ if (selectionStatus.current.type === 'table' && numberOfSelectedRows === numberOfSelectableRowsInTable - numberOfSelectableRowsInPage || selectionStatus.current.type === 'table' && numberOfSelectedRows === numberOfSelectableRowsInTable || selectionStatus.current.type === 'page' && numberOfSelectedRows === numberOfSelectableRowsInPage) {
1379
+ setTimeout(() => {
1380
+ apiRef.current.selectRows([], true, true);
1381
+ }, 0);
1382
+ }
1383
+ if (numberOfSelectedRows === numberOfSelectableRowsInPage && numberOfSelectableRowsInPage < numberOfSelectableRowsInTable) {
1384
+ selectionStatus.current = {
1385
+ type: 'page',
1386
+ numberOfSelectedRows
1387
+ };
1388
+ } else if (numberOfSelectedRows === numberOfSelectableRowsInTable && numberOfSelectableRowsInPage < numberOfSelectableRowsInTable) {
1389
+ selectionStatus.current = {
1390
+ type: 'table',
1391
+ numberOfSelectedRows
1392
+ };
1393
+ } else if (numberOfSelectedRows > 0) {
1394
+ selectionStatus.current = {
1395
+ type: 'other',
1396
+ numberOfSelectedRows
1397
+ };
1398
+ } else {
1399
+ selectionStatus.current = {
1400
+ type: 'none',
1401
+ numberOfSelectedRows
1402
+ };
1403
+ }
1404
+ }
1405
+ onSelectionModelChange === null || onSelectionModelChange === void 0 ? void 0 : onSelectionModelChange(newSelectionModel, details);
1406
+ },
1407
+ sx: _objectSpread2(_objectSpread2({}, sx), {}, {
1408
+ '.MuiDataGrid-columnHeaders': {
1409
+ flexDirection: 'column',
1410
+ alignItems: 'normal'
1411
+ },
1412
+ '.MuiDataGrid-selectedRowCount': {
1413
+ margin: 'none'
1414
+ }
1415
+ })
1416
+ })))));
1417
+ });
1418
+ StatefulDataGrid.className = CLASSNAME;
1419
+ StatefulDataGrid.displayName = COMPONENT_NAME;
18
1420
 
19
- export { StatefulDataGrid as S, StatefulDataGridProps as a };
1421
+ export { CATEGORIES as C, DIMENSION_MODEL_KEY as D, FILTER_MODEL_KEY as F, PAGINATION_MODEL_KEY as P, SORT_MODEL_KEY as S, VISIBILITY_MODEL_KEY as V, PINNED_COLUMNS as a, FILTER_SEARCH_KEY as b, buildStorageKey as c, clearPreviousVersionStorage as d, decodeValue as e, encodeValue as f, numberOperatorDecoder as g, getFilterModelFromString as h, getSearchParamsFromFilterModel as i, getSortingFromString as j, getSearchParamsFromSorting as k, getPaginationFromString as l, getSearchParamsFromPagination as m, numberOperatorEncoder as n, getSearchParamsFromColumnVisibility as o, getColumnVisibilityFromString as p, getPinnedColumnsFromString as q, getSearchParamsFromPinnedColumns as r, getSearchParamsFromTab as s, getFinalSearch as t, urlSearchParamsToString as u, getModelsParsedOrUpdateLocalStorage as v, updateUrl as w, areFilterModelsEquivalent as x, StatefulDataGrid as y };
1422
+ //# sourceMappingURL=StatefulDataGrid2.js.map