@redsift/table 12.5.8-muiv8-alpha.2 → 12.5.8-muiv8-alpha.4
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.
|
@@ -1565,7 +1565,7 @@ const isValueValid = (value, field, columns, operator) => {
|
|
|
1565
1565
|
|
|
1566
1566
|
// example:
|
|
1567
1567
|
// unicodeDomain[contains]=a&unicodeDomain[contains]=dsa&logicOperator=and&tab=ignored
|
|
1568
|
-
const getFilterModelFromString = (searchString, columns) => {
|
|
1568
|
+
const getFilterModelFromString = (searchString, columns, previousModel) => {
|
|
1569
1569
|
if (!searchString) {
|
|
1570
1570
|
return 'invalid';
|
|
1571
1571
|
}
|
|
@@ -1595,6 +1595,21 @@ const getFilterModelFromString = (searchString, columns) => {
|
|
|
1595
1595
|
}
|
|
1596
1596
|
}
|
|
1597
1597
|
let id = 5000;
|
|
1598
|
+
|
|
1599
|
+
// Positional id-reuse map keyed by `${field}|${operator}` (decoded operator, matching
|
|
1600
|
+
// the item we push below). FIFO per key so duplicate field+operator items map by order.
|
|
1601
|
+
// Reusing the id of a previously parsed/emitted item keeps `item.id` stable across the
|
|
1602
|
+
// URL write→parse roundtrip (the URL never carries the id), so MUI's GridFilterForm
|
|
1603
|
+
// React key does not change and the filter panel input keeps focus. (DS-81)
|
|
1604
|
+
const previousIdsByKey = new Map();
|
|
1605
|
+
if (previousModel) {
|
|
1606
|
+
for (const prev of previousModel.items) {
|
|
1607
|
+
if (prev.id === undefined) continue;
|
|
1608
|
+
const key = `${prev.field}|${prev.operator}`;
|
|
1609
|
+
const bucket = previousIdsByKey.get(key);
|
|
1610
|
+
if (bucket) bucket.push(prev.id);else previousIdsByKey.set(key, [prev.id]);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1598
1613
|
const fields = columns.map(column => column.field);
|
|
1599
1614
|
let isInvalid = false;
|
|
1600
1615
|
const items = [];
|
|
@@ -1630,10 +1645,13 @@ const getFilterModelFromString = (searchString, columns) => {
|
|
|
1630
1645
|
isInvalid = true;
|
|
1631
1646
|
return;
|
|
1632
1647
|
}
|
|
1648
|
+
const finalOperator = columnType === 'number' && Object.keys(numberOperatorDecoder).includes(operator) ? numberOperatorDecoder[operator] : operator;
|
|
1649
|
+
const reuseBucket = previousIdsByKey.get(`${field}|${finalOperator}`);
|
|
1650
|
+
const stableId = reuseBucket && reuseBucket.length > 0 ? reuseBucket.shift() : id;
|
|
1633
1651
|
items.push({
|
|
1634
1652
|
field,
|
|
1635
|
-
operator:
|
|
1636
|
-
id,
|
|
1653
|
+
operator: finalOperator,
|
|
1654
|
+
id: stableId,
|
|
1637
1655
|
value: listOperators.includes(operator) && decodedValue === '' ? [] : decodedValue,
|
|
1638
1656
|
type
|
|
1639
1657
|
});
|
|
@@ -1727,7 +1745,7 @@ const getSearchParamsFromFilterModel = filterModel => {
|
|
|
1727
1745
|
// - if we have something in the URL, use that info
|
|
1728
1746
|
// - if we don't have that, use the localStorage and update the URL
|
|
1729
1747
|
// - if we don't have that, return an empty FilterModel
|
|
1730
|
-
const getFilterModel = (search, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion) => {
|
|
1748
|
+
const getFilterModel = (search, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion, previousModel) => {
|
|
1731
1749
|
const defaultValue = initialState && initialState.filter && initialState.filter.filterModel ? initialState.filter.filterModel : {
|
|
1732
1750
|
items: [],
|
|
1733
1751
|
logicOperator: GridLogicOperator.And
|
|
@@ -1745,7 +1763,7 @@ const getFilterModel = (search, columns, localStorageFilters, setLocalStorageFil
|
|
|
1745
1763
|
persistDefaultFilters();
|
|
1746
1764
|
return defaultValue;
|
|
1747
1765
|
}
|
|
1748
|
-
const filterModelFromSearch = getFilterModelFromString(search, columns);
|
|
1766
|
+
const filterModelFromSearch = getFilterModelFromString(search, columns, previousModel);
|
|
1749
1767
|
if (filterModelFromSearch !== 'invalid') {
|
|
1750
1768
|
const searchFromFilterModel = getSearchParamsFromFilterModel(filterModelFromSearch);
|
|
1751
1769
|
const searchString = urlSearchParamsToString(searchFromFilterModel);
|
|
@@ -2610,7 +2628,7 @@ const getFinalSearch = _ref3 => {
|
|
|
2610
2628
|
return new URLSearchParams([...searchParams, ...filterModelSearch, ...sortModelSearch, ...paginationModelSearch, ...tabSearch, ...pinnedColumnsModelSearch, ...columnVisibilityModelSearch, ...densitySearch, ...columnOrderSearch, ...rowGroupingSearch, ...aggregationSearch, ...pivotSearch, ...pivotActiveSearch]);
|
|
2611
2629
|
};
|
|
2612
2630
|
/** Return the state of the table given the URL and the local storage state */
|
|
2613
|
-
const getModelsParsedOrUpdateLocalStorage = (search, localStorageVersion, columns, initialState, localStorage) => {
|
|
2631
|
+
const getModelsParsedOrUpdateLocalStorage = (search, localStorageVersion, columns, initialState, localStorage, previousFilterModel) => {
|
|
2614
2632
|
var _initialState$columns6, _initialState$columns7;
|
|
2615
2633
|
// Decompress any compressed params in the search string before processing
|
|
2616
2634
|
const decompressedSearch = decompressSearchParams(search);
|
|
@@ -2657,7 +2675,7 @@ const getModelsParsedOrUpdateLocalStorage = (search, localStorageVersion, column
|
|
|
2657
2675
|
localStoragePivotActive,
|
|
2658
2676
|
setLocalStoragePivotActive
|
|
2659
2677
|
} = localStorage;
|
|
2660
|
-
const filterModel = getFilterModel(decodedSearch, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion);
|
|
2678
|
+
const filterModel = getFilterModel(decodedSearch, columns, localStorageFilters, setLocalStorageFilters, initialState, isNewVersion, previousFilterModel);
|
|
2661
2679
|
const sortModel = getSortModel(decodedSearch, columns, localStorageSorting, setLocalStorageSorting, initialState, isNewVersion);
|
|
2662
2680
|
const paginationModel = getPaginationModel(decodedSearch, localStoragePagination, setLocalStoragePagination, initialState, isNewVersion);
|
|
2663
2681
|
const columnVisibilityModel = getColumnsVisibility(decodedSearch, columns, localStorageColumnsVisibility, setLocalStorageColumnsVisibility, initialState, isNewVersion);
|
|
@@ -3085,6 +3103,11 @@ const useStatefulTable = props => {
|
|
|
3085
3103
|
[field]: newWidth
|
|
3086
3104
|
}));
|
|
3087
3105
|
}, [dimensionModel, setDimensionModel]);
|
|
3106
|
+
|
|
3107
|
+
// Source of ids for content-matching in the parser, so item.id is stable across the
|
|
3108
|
+
// URL write→parse roundtrip (DS-81). Holds MUI's just-emitted model (random placeholder
|
|
3109
|
+
// id) after onFilterModelChange, then the stabilised parsed model each render.
|
|
3110
|
+
const filterIdSourceRef = useRef(undefined);
|
|
3088
3111
|
const {
|
|
3089
3112
|
filterModel: filterParsed,
|
|
3090
3113
|
sortModel: sortModelParsed,
|
|
@@ -3121,7 +3144,7 @@ const useStatefulTable = props => {
|
|
|
3121
3144
|
setLocalStoragePivot,
|
|
3122
3145
|
localStoragePivotActive: localStoragePivotActive,
|
|
3123
3146
|
setLocalStoragePivotActive: setLocalStoragePivotActive
|
|
3124
|
-
});
|
|
3147
|
+
}, filterIdSourceRef.current);
|
|
3125
3148
|
|
|
3126
3149
|
// Sync URL in an effect rather than during render to comply with React rules
|
|
3127
3150
|
useEffect(() => {
|
|
@@ -3136,6 +3159,10 @@ const useStatefulTable = props => {
|
|
|
3136
3159
|
if (!isDeepEqual(filterParsedRef.current, filterParsed)) {
|
|
3137
3160
|
filterParsedRef.current = filterParsed;
|
|
3138
3161
|
}
|
|
3162
|
+
// Keep the id source in sync with the stabilised parsed model so re-parses triggered
|
|
3163
|
+
// by unrelated state (pagination/sort/visibility) reuse the same ids (DS-81). The parse
|
|
3164
|
+
// call above reads the ref before this write (read-before-write within the render).
|
|
3165
|
+
filterIdSourceRef.current = filterParsed;
|
|
3139
3166
|
const sortModelParsedRef = useRef(sortModelParsed);
|
|
3140
3167
|
if (!isDeepEqual(sortModelParsedRef.current, sortModelParsed)) {
|
|
3141
3168
|
sortModelParsedRef.current = sortModelParsed;
|
|
@@ -3292,6 +3319,10 @@ const useStatefulTable = props => {
|
|
|
3292
3319
|
});
|
|
3293
3320
|
if (isDeepEqual(filterModel, lastEmittedFilterRef.current)) return;
|
|
3294
3321
|
lastEmittedFilterRef.current = filterModel;
|
|
3322
|
+
// Capture MUI's just-emitted model (carrying the placeholder's random id) so the
|
|
3323
|
+
// next render's URL re-parse reuses that id and the GridFilterForm key — and thus
|
|
3324
|
+
// the value input's focus — survives the write→parse roundtrip (DS-81).
|
|
3325
|
+
filterIdSourceRef.current = filterModel;
|
|
3295
3326
|
updateUrl(buildModel({
|
|
3296
3327
|
filterModel
|
|
3297
3328
|
}), search, localStorageVersion, historyReplace, columns);
|