@lavalogic/scoria 0.37.55 → 0.38.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/dist/Components/Table/ARCHITECTURE.md +22 -22
- package/dist/Components/Table/Misc/ColumnPanel.svelte +1 -61
- package/dist/Components/Table/Misc/ColumnPanel.svelte.d.ts +2 -24
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte +3 -92
- package/dist/Components/Table/Misc/ColumnPanelModal.svelte.d.ts +2 -24
- package/dist/Components/Table/Misc/ColumnPanelModalProps.d.ts +2 -2
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte +644 -0
- package/dist/Components/Table/Misc/TableConfigurationModal.svelte.d.ts +26 -0
- package/dist/Components/Table/Misc/TableConfigurationModalProps.d.ts +13 -0
- package/dist/Components/Table/Misc/TableHorizontalBar.svelte +27 -0
- package/dist/Components/Table/Misc/TableSidebar.svelte +45 -2
- package/dist/Components/Table/Misc/TableViewDropdown.svelte +175 -0
- package/dist/Components/Table/Misc/TableViewDropdown.svelte.d.ts +25 -0
- package/dist/Components/Table/SubApis.svelte.js +0 -41
- package/dist/Components/Table/Types/Columns/JSONTableLayout.d.ts +5 -5
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.d.ts +5 -5
- package/dist/Components/Table/Types/Context/ColumnLayoutState.svelte.js +5 -5
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.d.ts +106 -147
- package/dist/Components/Table/Types/Context/PreferencesState.svelte.js +156 -203
- package/dist/Components/Table/Types/Context/TableContext.svelte.d.ts +323 -44
- package/dist/Components/Table/Types/Context/TableContext.svelte.js +687 -187
- package/dist/Components/Table/Types/Context/TableInitOptions.d.ts +9 -0
- package/dist/Components/Table/Types/Context/ViewState.svelte.d.ts +152 -0
- package/dist/Components/Table/Types/Context/ViewState.svelte.js +223 -0
- package/dist/Components/Table/Types/ExpandedPanel.d.ts +9 -5
- package/dist/Components/Table/Types/ExpandedPanel.js +9 -5
- package/dist/Components/Table/Types/Persistence/DatatableView.d.ts +95 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewEnvelope.d.ts +21 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewEnvelope.js +1 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewKind.d.ts +10 -0
- package/dist/Components/Table/Types/Persistence/DatatableViewKind.js +1 -0
- package/dist/Components/Table/Types/Persistence/JSONActiveView.d.ts +58 -0
- package/dist/Components/Table/Types/Persistence/JSONActiveView.js +41 -0
- package/dist/Components/Table/Types/Persistence/JSONTableFilter.d.ts +53 -0
- package/dist/Components/Table/Types/Persistence/JSONTableFilter.js +42 -0
- package/dist/Components/Table/Types/Persistence/RemoteTableLayoutAdapter.d.ts +47 -0
- package/dist/Components/Table/Types/Persistence/RemoteTableLayoutAdapter.js +1 -0
- package/dist/Components/Table/Types/Public/CreateTableOptions.d.ts +10 -0
- package/dist/Components/Table/Types/Public/TablePersistence.d.ts +1 -4
- package/dist/Components/Table/Types/Public/TableSubApis.d.ts +0 -18
- package/dist/Components/Table/Types/Public/index.d.ts +1 -1
- package/dist/Components/Table/createTable.svelte.js +2 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +9 -0
- package/package.json +1 -1
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDefSet.d.ts +0 -20
- package/dist/Components/Table/Types/Columns/Definitions/JSONColumnDefSet.d.ts +0 -25
- /package/dist/Components/Table/{Types/Columns/Definitions/ColumnDefSet.js → Misc/TableConfigurationModalProps.js} +0 -0
- /package/dist/Components/Table/Types/{Columns/Definitions/JSONColumnDefSet.js → Persistence/DatatableView.js} +0 -0
|
@@ -1,25 +1,8 @@
|
|
|
1
1
|
import { dev } from '$app/environment';
|
|
2
2
|
import { readJSON, readVersionedJSON, writeJSON } from '../../../../Helpers/Storage.js';
|
|
3
3
|
import { isJSONTableLayout, TABLE_LAYOUT_SCHEMA_VERSION, } from '../Columns/JSONTableLayout.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* same-origin-writable so only the array shape can be trusted;
|
|
7
|
-
* downstream `reassignDefsToPresets` performs deeper checks and drops
|
|
8
|
-
* presets that fail. Asserts the outer envelope plus the bare minimum
|
|
9
|
-
* per entry: a string `name` and an array `columnDefs`.
|
|
10
|
-
*/
|
|
11
|
-
export function isJSONColumnDefSetArray(raw) {
|
|
12
|
-
if (!Array.isArray(raw)) {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
return raw.every((entry) => {
|
|
16
|
-
if (typeof entry !== 'object' || entry === null) {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
const candidate = entry;
|
|
20
|
-
return typeof candidate.name === 'string' && Array.isArray(candidate.columnDefs);
|
|
21
|
-
});
|
|
22
|
-
}
|
|
4
|
+
import { isJSONActiveView, TABLE_ACTIVE_VIEW_SCHEMA_VERSION, } from '../Persistence/JSONActiveView.js';
|
|
5
|
+
import { isJSONTableFilter, TABLE_FILTER_SCHEMA_VERSION, } from '../Persistence/JSONTableFilter.js';
|
|
23
6
|
/**
|
|
24
7
|
* Typeguard for the persisted user-level table settings blob. Every
|
|
25
8
|
* field is optional, but every present field must be boolean; anything
|
|
@@ -38,34 +21,22 @@ export function isSavedTableSettings(raw) {
|
|
|
38
21
|
optionalBoolean('copyWithHeaders') &&
|
|
39
22
|
optionalBoolean('commaSeparatedCopy'));
|
|
40
23
|
}
|
|
41
|
-
/**
|
|
42
|
-
* Typeguard for a non-empty string. Used for the persisted selected
|
|
43
|
-
* preset name slot.
|
|
44
|
-
*/
|
|
45
|
-
export function isNonEmptyString(raw) {
|
|
46
|
-
return typeof raw === 'string' && raw.length > 0;
|
|
47
|
-
}
|
|
48
24
|
/**
|
|
49
25
|
* Sub-context owning every persistence / preferences concern:
|
|
50
26
|
*
|
|
51
|
-
* - `_columnPresets` (persisted preset list `$state`);
|
|
52
|
-
* - `_selectedPreset` (currently-active preset `$state`);
|
|
53
27
|
* - `userIdSegment` (sanitised user-id segment used in storage keys;
|
|
54
28
|
* `$derived` over `getUserId()`);
|
|
55
|
-
* - `
|
|
56
|
-
*
|
|
57
|
-
* - `
|
|
58
|
-
*
|
|
59
|
-
* - `
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* `
|
|
63
|
-
*
|
|
64
|
-
* - `
|
|
65
|
-
*
|
|
66
|
-
* - schema-validation typeguards (`isJSONColumnDefSetArray`,
|
|
67
|
-
* `isSavedTableSettings`, `isNonEmptyString`) - exported alongside
|
|
68
|
-
* the class.
|
|
29
|
+
* - `loadSavedSettings()` / `persistSettings()` (the per-table
|
|
30
|
+
* TableSettings blob: compact, alternate rows, etc.);
|
|
31
|
+
* - `loadLayout()` / `persistLayout()` / `clearLayout()` (the
|
|
32
|
+
* auto-saved live-layout working copy);
|
|
33
|
+
* - `loadActiveView()` / `persistActiveView()` / `clearActiveView()`
|
|
34
|
+
* (the DB-backed view selection envelope);
|
|
35
|
+
* - the filter counterparts (`loadFilter` / `persistFilter` /
|
|
36
|
+
* `clearFilter`, `loadActiveFilterView` / `persistActiveFilterView` /
|
|
37
|
+
* `clearActiveFilterView`);
|
|
38
|
+
* - schema-validation typeguards (`isSavedTableSettings`) - exported
|
|
39
|
+
* alongside the class.
|
|
69
40
|
*
|
|
70
41
|
* Every `localStorage` access is funnelled through this sub-context so
|
|
71
42
|
* the `scoria-table:<user>:<tableName>:<suffix>` namespace convention
|
|
@@ -73,15 +44,11 @@ export function isNonEmptyString(raw) {
|
|
|
73
44
|
*/
|
|
74
45
|
export class PreferencesState {
|
|
75
46
|
_deps;
|
|
76
|
-
_columnPresets = $state([]);
|
|
77
|
-
//FIXME why is this allowed to be undefined? Retained as
|
|
78
|
-
// `undefined`-capable for backwards source compatibility.
|
|
79
|
-
_selectedPreset = $state();
|
|
80
47
|
/**
|
|
81
48
|
* Sanitised segment of the persisted-storage key path. Resolves to
|
|
82
49
|
* `getUserId() ?? 'anon'` so different users on a shared browser
|
|
83
|
-
* cannot read each other's
|
|
84
|
-
* sessions still have a stable namespace.
|
|
50
|
+
* cannot read each other's persisted layout / filter state, and so
|
|
51
|
+
* anonymous sessions still have a stable namespace.
|
|
85
52
|
*
|
|
86
53
|
* The `$derived.by` form is required here (over plain
|
|
87
54
|
* `$derived(expr)`) because class-field initialisers run BEFORE
|
|
@@ -98,77 +65,19 @@ export class PreferencesState {
|
|
|
98
65
|
this._deps = deps;
|
|
99
66
|
}
|
|
100
67
|
/**
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* the
|
|
104
|
-
|
|
105
|
-
get columnPresets() {
|
|
106
|
-
return this._columnPresets;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Writer for `columnPresets`. Public so the parent boot flow can
|
|
110
|
-
* publish the hydrated list; not part of the consumer-facing
|
|
111
|
-
* surface (consumer-facing writes go through `saveColumnPreset`).
|
|
112
|
-
*/
|
|
113
|
-
setPresets(v) {
|
|
114
|
-
this._columnPresets = v;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* The currently-active preset (the one whose name is persisted in
|
|
118
|
-
* the `selected-preset-name` slot). Setter is public so the parent
|
|
119
|
-
* boot flow can publish the resolved preset; the consumer-facing
|
|
120
|
-
* writer is `setSelectedPreset` below (which also persists the
|
|
121
|
-
* name).
|
|
122
|
-
*/
|
|
123
|
-
get selectedPreset() {
|
|
124
|
-
return this._selectedPreset;
|
|
125
|
-
}
|
|
126
|
-
set selectedPreset(v) {
|
|
127
|
-
this._selectedPreset = v;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Build the canonical `scoria-table:<user>:<tableName>:<suffix>`
|
|
131
|
-
* storage key. Centralised so every persisted-state slot reaches
|
|
132
|
-
* for the same namespacing convention; the `<user>` segment is
|
|
133
|
-
* `getUserId() ?? 'anon'` (see `userIdSegment`).
|
|
134
|
-
*/
|
|
135
|
-
storageKey(suffix) {
|
|
136
|
-
return `scoria-table:${this.userIdSegment}:${this._deps.getTableName()}:${suffix}`;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Boot-time hydration helper. Reads the persisted preset list from
|
|
140
|
-
* `localStorage`, validates it against `isJSONColumnDefSetArray`,
|
|
141
|
-
* and returns the parsed array (or an empty array on every failure
|
|
142
|
-
* path). The parent runs this once `setupDefaultColumnDefs` has
|
|
143
|
-
* completed so the live `columnDefs` can be compared against the
|
|
144
|
-
* persisted snapshot.
|
|
68
|
+
* Build the canonical `scoria-table:<user>:<scope>:<suffix>` storage
|
|
69
|
+
* key. Centralised so every persisted-state slot reaches for the same
|
|
70
|
+
* namespacing convention; the `<user>` segment is `getUserId() ??
|
|
71
|
+
* 'anon'` (see `userIdSegment`).
|
|
145
72
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
73
|
+
* The `<scope>` segment is the host-supplied `datatableUuid` when one
|
|
74
|
+
* is present, falling back to the table `name`. Preferring the UUID
|
|
75
|
+
* keeps two tables that share a `name` option from colliding on the
|
|
76
|
+
* same localStorage slots.
|
|
148
77
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Boot-time hydration helper. Reads the persisted selected-preset
|
|
154
|
-
* name. Returns `null` for missing / empty / storage-error slots
|
|
155
|
-
* so the parent can fall back to the first preset (or the default).
|
|
156
|
-
* Emits a dev-only warning on `getItem` failure.
|
|
157
|
-
*/
|
|
158
|
-
loadSelectedPresetName() {
|
|
159
|
-
let savedPresetName = null;
|
|
160
|
-
try {
|
|
161
|
-
savedPresetName = localStorage.getItem(this.storageKey('selected-preset-name'));
|
|
162
|
-
}
|
|
163
|
-
catch (e) {
|
|
164
|
-
if (dev) {
|
|
165
|
-
console.warn('selected-preset-name read failed:', e);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
if (!isNonEmptyString(savedPresetName)) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
return savedPresetName;
|
|
78
|
+
storageKey(suffix) {
|
|
79
|
+
const scope = this._deps.getDatatableUuid() ?? this._deps.getTableName();
|
|
80
|
+
return `scoria-table:${this.userIdSegment}:${scope}:${suffix}`;
|
|
172
81
|
}
|
|
173
82
|
/**
|
|
174
83
|
* Boot-time hydration helper. Reads the persisted per-table
|
|
@@ -184,15 +93,6 @@ export class PreferencesState {
|
|
|
184
93
|
}
|
|
185
94
|
return saved;
|
|
186
95
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Drop the persisted presets and selected-preset-name slots. Used
|
|
189
|
-
* by the parent's boot flow when the saved snapshot disagrees with
|
|
190
|
-
* the live column-def shape (schema drift or column-set change).
|
|
191
|
-
*/
|
|
192
|
-
clearPresetsAndSelection() {
|
|
193
|
-
localStorage.removeItem(this.storageKey('presets'));
|
|
194
|
-
localStorage.removeItem(this.storageKey('selected-preset-name'));
|
|
195
|
-
}
|
|
196
96
|
/**
|
|
197
97
|
* Boot-time hydration helper. Reads the auto-saved live-layout
|
|
198
98
|
* snapshot (column order / visibility / pinning / sizing the user
|
|
@@ -241,98 +141,151 @@ export class PreferencesState {
|
|
|
241
141
|
}
|
|
242
142
|
}
|
|
243
143
|
/**
|
|
244
|
-
*
|
|
245
|
-
* envelope
|
|
144
|
+
* Boot-time hydration helper. Reads the persisted active-view
|
|
145
|
+
* envelope (which saved view, if any, the live working copy belongs
|
|
146
|
+
* to, plus its dirty flag). Returns `null` for a missing slot, a
|
|
147
|
+
* schema-version mismatch, or a value that fails validation, so the
|
|
148
|
+
* parent can fall back to the Default view.
|
|
149
|
+
*
|
|
150
|
+
* `localStorage` access is gated by the parent's `browser` check;
|
|
151
|
+
* this method assumes the caller already verified the environment.
|
|
246
152
|
*/
|
|
247
|
-
|
|
248
|
-
|
|
153
|
+
loadActiveView() {
|
|
154
|
+
// Reference-equality sentinel: `readVersionedJSON` demands a
|
|
155
|
+
// fallback of the value type, so a distinct object instance is
|
|
156
|
+
// used to distinguish "no usable slot" from a real snapshot.
|
|
157
|
+
const fallback = {
|
|
158
|
+
active: { kind: 'default' },
|
|
159
|
+
dirty: false,
|
|
160
|
+
};
|
|
161
|
+
const saved = readVersionedJSON(localStorage, this.storageKey('active-view'), TABLE_ACTIVE_VIEW_SCHEMA_VERSION, isJSONActiveView, fallback);
|
|
162
|
+
return saved === fallback ? null : saved;
|
|
249
163
|
}
|
|
250
164
|
/**
|
|
251
|
-
* Persist the
|
|
252
|
-
*
|
|
165
|
+
* Persist the active-view envelope. Written by the parent (debounced,
|
|
166
|
+
* alongside the working-copy layout) on every layout change, wrapped
|
|
167
|
+
* in a versioned envelope so a future schema bump drops stale
|
|
168
|
+
* snapshots cleanly. Storage failures are swallowed inside
|
|
169
|
+
* `writeJSON`.
|
|
253
170
|
*/
|
|
254
|
-
|
|
255
|
-
localStorage
|
|
171
|
+
persistActiveView(v) {
|
|
172
|
+
writeJSON(localStorage, this.storageKey('active-view'), v, TABLE_ACTIVE_VIEW_SCHEMA_VERSION);
|
|
256
173
|
}
|
|
257
174
|
/**
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
* because Map does not survive `JSON.stringify`; the reader (via
|
|
261
|
-
* `loadPresets` -> `reassignDefsToPresets`) rehydrates it through
|
|
262
|
-
* `adaptJSONPinningState`.
|
|
175
|
+
* Drop the persisted active-view envelope. Called when table state is
|
|
176
|
+
* explicitly reset; the next mount falls back to the Default view.
|
|
263
177
|
*/
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
right: [...(preset.columnPinningState.right?.entries() ?? [])],
|
|
274
|
-
},
|
|
275
|
-
};
|
|
276
|
-
});
|
|
277
|
-
localStorage.setItem(this.storageKey('presets'), JSON.stringify(jsonFriendly));
|
|
178
|
+
clearActiveView() {
|
|
179
|
+
try {
|
|
180
|
+
localStorage.removeItem(this.storageKey('active-view'));
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
if (dev) {
|
|
184
|
+
console.warn('table active-view slot clear failed:', e);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
278
187
|
}
|
|
279
188
|
/**
|
|
280
|
-
*
|
|
281
|
-
* the
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* 3. Update `selectedPreset`.
|
|
287
|
-
* 4. Persist the preset name to `selected-preset-name`.
|
|
189
|
+
* Boot-time hydration helper. Reads the auto-saved live-filter
|
|
190
|
+
* snapshot (the per-column filter values and modes the user built up
|
|
191
|
+
* in the quick-filter row / advanced filter panel without saving a
|
|
192
|
+
* named view). Returns `null` for a missing slot, a schema-version
|
|
193
|
+
* mismatch, or a value that fails validation, so the parent can fall
|
|
194
|
+
* back to the empty filter state.
|
|
288
195
|
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
196
|
+
* The filter counterpart of `loadLayout`. `localStorage` access is
|
|
197
|
+
* gated by the parent's `browser` check; this method assumes the
|
|
198
|
+
* caller already verified the environment.
|
|
291
199
|
*/
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.
|
|
301
|
-
|
|
302
|
-
}
|
|
200
|
+
loadFilter() {
|
|
201
|
+
// Reference-equality sentinel: `readVersionedJSON` demands a
|
|
202
|
+
// fallback of the value type, so a distinct object instance is
|
|
203
|
+
// used to distinguish "no usable slot" from a real snapshot.
|
|
204
|
+
const fallback = {
|
|
205
|
+
filters: [],
|
|
206
|
+
modes: {},
|
|
207
|
+
};
|
|
208
|
+
const saved = readVersionedJSON(localStorage, this.storageKey('filter'), TABLE_FILTER_SCHEMA_VERSION, isJSONTableFilter, fallback);
|
|
209
|
+
return saved === fallback ? null : saved;
|
|
210
|
+
}
|
|
303
211
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
212
|
+
* Persist the live-filter snapshot. Written by the parent (debounced)
|
|
213
|
+
* on every filter value / mode change, wrapped in a versioned
|
|
214
|
+
* envelope so a future schema bump drops stale snapshots cleanly.
|
|
215
|
+
* Storage failures are swallowed inside `writeJSON`. The filter
|
|
216
|
+
* counterpart of `persistLayout`.
|
|
309
217
|
*/
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
218
|
+
persistFilter(filter) {
|
|
219
|
+
writeJSON(localStorage, this.storageKey('filter'), filter, TABLE_FILTER_SCHEMA_VERSION);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Drop the persisted live-filter snapshot. Called when the snapshot
|
|
223
|
+
* no longer matches the table's column set (schema drift) or when
|
|
224
|
+
* table state is explicitly reset. The filter counterpart of
|
|
225
|
+
* `clearLayout`.
|
|
226
|
+
*/
|
|
227
|
+
clearFilter() {
|
|
228
|
+
try {
|
|
229
|
+
localStorage.removeItem(this.storageKey('filter'));
|
|
313
230
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
231
|
+
catch (e) {
|
|
232
|
+
if (dev) {
|
|
233
|
+
console.warn('table filter slot clear failed:', e);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Boot-time hydration helper. Reads the persisted *filter*
|
|
239
|
+
* active-view envelope (which saved filter view, if any, the live
|
|
240
|
+
* filter working copy belongs to, plus its dirty flag). Returns
|
|
241
|
+
* `null` for a missing slot, a schema-version mismatch, or a value
|
|
242
|
+
* that fails validation, so the parent can fall back to the Default
|
|
243
|
+
* filter view. The filter counterpart of `loadActiveView`.
|
|
244
|
+
*
|
|
245
|
+
* `localStorage` access is gated by the parent's `browser` check;
|
|
246
|
+
* this method assumes the caller already verified the environment.
|
|
247
|
+
*/
|
|
248
|
+
loadActiveFilterView() {
|
|
249
|
+
// Reference-equality sentinel: `readVersionedJSON` demands a
|
|
250
|
+
// fallback of the value type, so a distinct object instance is
|
|
251
|
+
// used to distinguish "no usable slot" from a real snapshot.
|
|
252
|
+
const fallback = {
|
|
253
|
+
active: { kind: 'default' },
|
|
254
|
+
dirty: false,
|
|
324
255
|
};
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
256
|
+
const saved = readVersionedJSON(localStorage, this.storageKey('active-filter-view'), TABLE_ACTIVE_VIEW_SCHEMA_VERSION, isJSONActiveView, fallback);
|
|
257
|
+
return saved === fallback ? null : saved;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Persist the *filter* active-view envelope. Written by the parent
|
|
261
|
+
* (debounced, alongside the working-copy filter) on every filter
|
|
262
|
+
* change, wrapped in a versioned envelope so a future schema bump
|
|
263
|
+
* drops stale snapshots cleanly. Storage failures are swallowed
|
|
264
|
+
* inside `writeJSON`. The filter counterpart of `persistActiveView`.
|
|
265
|
+
*/
|
|
266
|
+
persistActiveFilterView(v) {
|
|
267
|
+
writeJSON(localStorage, this.storageKey('active-filter-view'), v, TABLE_ACTIVE_VIEW_SCHEMA_VERSION);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Drop the persisted *filter* active-view envelope. Called when table
|
|
271
|
+
* state is explicitly reset; the next mount falls back to the Default
|
|
272
|
+
* filter view. The filter counterpart of `clearActiveView`.
|
|
273
|
+
*/
|
|
274
|
+
clearActiveFilterView() {
|
|
275
|
+
try {
|
|
276
|
+
localStorage.removeItem(this.storageKey('active-filter-view'));
|
|
330
277
|
}
|
|
331
|
-
|
|
332
|
-
|
|
278
|
+
catch (e) {
|
|
279
|
+
if (dev) {
|
|
280
|
+
console.warn('table active-filter-view slot clear failed:', e);
|
|
281
|
+
}
|
|
333
282
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Persist the per-table settings blob (`isCompact`,
|
|
286
|
+
* `singleClickEditing`, etc.) as JSON.
|
|
287
|
+
*/
|
|
288
|
+
persistSettings(settings) {
|
|
289
|
+
localStorage.setItem(this.storageKey('settings'), JSON.stringify(settings));
|
|
290
|
+
}
|
|
338
291
|
}
|