@lavalogic/scoria 0.38.4 → 0.38.6
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.
|
Binary file
|
|
@@ -37,6 +37,31 @@ const LAYOUT_PERSIST_DEBOUNCE_MS = 250;
|
|
|
37
37
|
* auto-persist effects behave consistently.
|
|
38
38
|
*/
|
|
39
39
|
const FILTER_PERSIST_DEBOUNCE_MS = 250;
|
|
40
|
+
/**
|
|
41
|
+
* `JSON.stringify` with object keys sorted recursively, so two
|
|
42
|
+
* structurally-equal values produce an identical string regardless of
|
|
43
|
+
* key insertion order. Array element order is preserved (it is
|
|
44
|
+
* significant for `columnOrder` and pinning entries).
|
|
45
|
+
*
|
|
46
|
+
* Used for the layout / filter dirty comparison: a baseline parsed from a
|
|
47
|
+
* backend JSON column has arbitrary key order, while `_captureLayout` /
|
|
48
|
+
* `_captureFilter` build their objects in a fixed order - a plain
|
|
49
|
+
* `JSON.stringify` compare would then report a false "dirty" the moment a
|
|
50
|
+
* saved view is applied.
|
|
51
|
+
*/
|
|
52
|
+
function stableStringify(value) {
|
|
53
|
+
if (value === null || typeof value !== 'object') {
|
|
54
|
+
return JSON.stringify(value) ?? 'null';
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
return `[${value.map(stableStringify).join(',')}]`;
|
|
58
|
+
}
|
|
59
|
+
const record = value;
|
|
60
|
+
return `{${Object.keys(record)
|
|
61
|
+
.sort()
|
|
62
|
+
.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`)
|
|
63
|
+
.join(',')}}`;
|
|
64
|
+
}
|
|
40
65
|
/**
|
|
41
66
|
* The complete set of filter-mode operator strings scoria recognises -
|
|
42
67
|
* the union of every `StringFilterMode` and `NumberDateFilterMode`
|
|
@@ -412,13 +437,14 @@ export class TableContext {
|
|
|
412
437
|
this._layoutPersistTimer = undefined;
|
|
413
438
|
this._preferences.persistLayout(snapshot);
|
|
414
439
|
// Dirty tracking: the layout is dirty when it diverges
|
|
415
|
-
// from the active view's baseline.
|
|
416
|
-
//
|
|
417
|
-
//
|
|
418
|
-
//
|
|
419
|
-
//
|
|
440
|
+
// from the active view's baseline. The baseline can be a
|
|
441
|
+
// layout parsed from a backend JSON column (arbitrary key
|
|
442
|
+
// order), so the comparison must be key-order-insensitive
|
|
443
|
+
// - a plain `JSON.stringify` compare flagged every applied
|
|
444
|
+
// saved view as dirty. When no baseline has been captured
|
|
445
|
+
// yet (should not happen past boot) treat it as clean.
|
|
420
446
|
const differs = this._viewBaseline !== undefined &&
|
|
421
|
-
|
|
447
|
+
stableStringify(snapshot) !== stableStringify(this._viewBaseline);
|
|
422
448
|
this._viewState.markDirty('layout', differs);
|
|
423
449
|
this._persistActiveView();
|
|
424
450
|
}, LAYOUT_PERSIST_DEBOUNCE_MS);
|
|
@@ -449,13 +475,13 @@ export class TableContext {
|
|
|
449
475
|
this._filterPersistTimer = undefined;
|
|
450
476
|
this._preferences.persistFilter(snapshot);
|
|
451
477
|
// Dirty tracking: the filter is dirty when it diverges from
|
|
452
|
-
// the active filter view's baseline.
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
// not happen past boot) treat the filter as clean.
|
|
478
|
+
// the active filter view's baseline. The baseline can be a
|
|
479
|
+
// filter parsed from a backend JSON column (arbitrary key
|
|
480
|
+
// order), so the comparison is key-order-insensitive via
|
|
481
|
+
// `stableStringify`. When no baseline has been captured yet
|
|
482
|
+
// (should not happen past boot) treat the filter as clean.
|
|
457
483
|
const differs = this._filterBaseline !== undefined &&
|
|
458
|
-
|
|
484
|
+
stableStringify(snapshot) !== stableStringify(this._filterBaseline);
|
|
459
485
|
this._viewState.markDirty('filter', differs);
|
|
460
486
|
this._persistActiveFilterView();
|
|
461
487
|
}, FILTER_PERSIST_DEBOUNCE_MS);
|