@xh/hoist 70.0.0-SNAPSHOT.1731083521069 → 70.0.0-SNAPSHOT.1731374612473
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/build/types/cmp/filter/FilterChooserModel.d.ts +17 -12
- package/build/types/cmp/grid/GridModel.d.ts +5 -9
- package/build/types/cmp/grid/Types.d.ts +7 -19
- package/build/types/cmp/grid/columns/Column.d.ts +0 -1
- package/build/types/cmp/grid/impl/InitPersist.d.ts +7 -0
- package/build/types/cmp/grouping/GroupingChooserModel.d.ts +6 -8
- package/build/types/cmp/tab/TabContainerModel.d.ts +10 -4
- package/build/types/cmp/zoneGrid/Types.d.ts +6 -6
- package/build/types/cmp/zoneGrid/ZoneGridModel.d.ts +0 -2
- package/build/types/cmp/zoneGrid/impl/InitPersist.d.ts +7 -0
- package/build/types/core/HoistBase.d.ts +1 -1
- package/build/types/core/persist/CustomProvider.d.ts +5 -6
- package/build/types/core/persist/DashViewProvider.d.ts +6 -6
- package/build/types/core/persist/LocalStorageProvider.d.ts +4 -5
- package/build/types/core/persist/PersistOptions.d.ts +5 -4
- package/build/types/core/persist/Persistable.d.ts +14 -0
- package/build/types/core/persist/PersistenceProvider.d.ts +47 -34
- package/build/types/core/persist/PrefProvider.d.ts +5 -5
- package/build/types/core/persist/index.d.ts +2 -0
- package/build/types/core/persist/viewmanager/Types.d.ts +46 -0
- package/build/types/core/persist/viewmanager/ViewManagerModel.d.ts +149 -0
- package/build/types/core/persist/viewmanager/ViewManagerProvider.d.ts +10 -0
- package/build/types/core/persist/viewmanager/impl/ManageDialogModel.d.ts +30 -0
- package/build/types/core/persist/viewmanager/impl/SaveDialogModel.d.ts +23 -0
- package/build/types/core/persist/viewmanager/index.d.ts +2 -0
- package/build/types/desktop/cmp/button/ColAutosizeButton.d.ts +1 -1
- package/build/types/desktop/cmp/dash/DashConfig.d.ts +3 -1
- package/build/types/desktop/cmp/dash/DashModel.d.ts +1 -2
- package/build/types/desktop/cmp/dash/DashViewSpec.d.ts +1 -1
- package/build/types/desktop/cmp/dash/canvas/DashCanvasModel.d.ts +10 -2
- package/build/types/desktop/cmp/dash/container/DashContainerModel.d.ts +26 -10
- package/build/types/desktop/cmp/dash/container/impl/DashContainerUtils.d.ts +4 -2
- package/build/types/desktop/cmp/panel/PanelModel.d.ts +8 -4
- package/build/types/desktop/cmp/viewmanager/ViewManager.d.ts +22 -0
- package/build/types/desktop/cmp/viewmanager/cmp/ManageDialog.d.ts +6 -0
- package/build/types/desktop/cmp/viewmanager/cmp/SaveDialog.d.ts +2 -0
- package/build/types/desktop/cmp/viewmanager/index.d.ts +3 -0
- package/build/types/kit/blueprint/Wrappers.d.ts +1 -1
- package/build/types/mobile/cmp/button/ColAutosizeButton.d.ts +1 -1
- package/build/types/svc/GridAutosizeService.d.ts +2 -5
- package/build/types/svc/JsonBlobService.d.ts +45 -24
- package/cmp/filter/FilterChooserModel.ts +142 -125
- package/cmp/grid/Grid.ts +2 -10
- package/cmp/grid/GridModel.ts +18 -31
- package/cmp/grid/Types.ts +7 -21
- package/cmp/grid/columns/Column.ts +0 -1
- package/cmp/grid/impl/InitPersist.ts +71 -0
- package/cmp/grouping/GroupingChooserModel.ts +48 -57
- package/cmp/tab/TabContainerModel.ts +22 -36
- package/cmp/zoneGrid/Types.ts +6 -6
- package/cmp/zoneGrid/ZoneGridModel.ts +2 -7
- package/cmp/zoneGrid/impl/InitPersist.ts +70 -0
- package/core/HoistBase.ts +14 -22
- package/core/HoistBaseDecorators.ts +26 -28
- package/core/persist/CustomProvider.ts +7 -10
- package/core/persist/DashViewProvider.ts +8 -10
- package/core/persist/LocalStorageProvider.ts +9 -12
- package/core/persist/PersistOptions.ts +6 -4
- package/core/persist/Persistable.ts +23 -0
- package/core/persist/PersistenceProvider.ts +159 -79
- package/core/persist/PrefProvider.ts +9 -12
- package/core/persist/index.ts +2 -0
- package/core/persist/viewmanager/Types.ts +51 -0
- package/core/persist/viewmanager/ViewManagerModel.ts +515 -0
- package/core/persist/viewmanager/ViewManagerProvider.ts +51 -0
- package/core/persist/viewmanager/impl/ManageDialogModel.ts +274 -0
- package/core/persist/viewmanager/impl/SaveDialogModel.ts +112 -0
- package/core/persist/viewmanager/index.ts +2 -0
- package/desktop/cmp/button/ColAutosizeButton.ts +1 -1
- package/desktop/cmp/dash/DashConfig.ts +3 -1
- package/desktop/cmp/dash/DashModel.ts +1 -2
- package/desktop/cmp/dash/DashViewSpec.ts +1 -1
- package/desktop/cmp/dash/canvas/DashCanvasModel.ts +31 -30
- package/desktop/cmp/dash/container/DashContainerModel.ts +68 -43
- package/desktop/cmp/dash/container/impl/DashContainerUtils.ts +13 -4
- package/desktop/cmp/leftrightchooser/LeftRightChooserFilter.ts +1 -1
- package/desktop/cmp/panel/PanelModel.ts +33 -53
- package/desktop/cmp/store/impl/StoreFilterField.ts +1 -1
- package/desktop/cmp/viewmanager/ViewManager.scss +58 -0
- package/desktop/cmp/viewmanager/ViewManager.ts +274 -0
- package/desktop/cmp/viewmanager/cmp/ManageDialog.ts +197 -0
- package/desktop/cmp/viewmanager/cmp/SaveDialog.ts +89 -0
- package/desktop/cmp/viewmanager/index.ts +3 -0
- package/mobile/cmp/button/ColAutosizeButton.ts +1 -1
- package/package.json +1 -1
- package/svc/GridAutosizeService.ts +73 -36
- package/svc/JsonBlobService.ts +64 -31
- package/tsconfig.tsbuildinfo +1 -1
- package/build/types/cmp/grid/impl/GridPersistenceModel.d.ts +0 -41
- package/build/types/cmp/zoneGrid/impl/ZoneGridPersistenceModel.d.ts +0 -39
- package/cmp/grid/impl/GridPersistenceModel.ts +0 -174
- package/cmp/zoneGrid/impl/ZoneGridPersistenceModel.ts +0 -149
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
import {PersistableState, PersistenceProvider} from '@xh/hoist/core';
|
|
8
|
+
import {isObject} from 'lodash';
|
|
9
|
+
import {GridModel} from '../GridModel';
|
|
10
|
+
import {GridModelPersistOptions} from '../Types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initialize persistence for a {@link GridModel} by applying its `persistWith` config.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function initPersist(
|
|
17
|
+
gridModel: GridModel,
|
|
18
|
+
{
|
|
19
|
+
persistColumns = true,
|
|
20
|
+
persistGrouping = true,
|
|
21
|
+
persistSort = true,
|
|
22
|
+
path = 'grid',
|
|
23
|
+
...rootPersistWith
|
|
24
|
+
}: GridModelPersistOptions
|
|
25
|
+
) {
|
|
26
|
+
if (persistColumns) {
|
|
27
|
+
const persistWith = isObject(persistColumns) ? persistColumns : rootPersistWith;
|
|
28
|
+
PersistenceProvider.create({
|
|
29
|
+
persistOptions: {
|
|
30
|
+
path: `${path}.columns`,
|
|
31
|
+
...persistWith
|
|
32
|
+
},
|
|
33
|
+
target: {
|
|
34
|
+
getPersistableState: () => new PersistableState(gridModel.persistableColumnState),
|
|
35
|
+
setPersistableState: ({value}) => gridModel.setColumnState(value)
|
|
36
|
+
},
|
|
37
|
+
owner: gridModel
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (persistSort) {
|
|
42
|
+
const persistWith = isObject(persistSort) ? persistSort : rootPersistWith;
|
|
43
|
+
PersistenceProvider.create({
|
|
44
|
+
persistOptions: {
|
|
45
|
+
path: `${path}.sortBy`,
|
|
46
|
+
...persistWith
|
|
47
|
+
},
|
|
48
|
+
target: {
|
|
49
|
+
getPersistableState: () =>
|
|
50
|
+
new PersistableState(gridModel.sortBy.map(it => it.toString())),
|
|
51
|
+
setPersistableState: ({value}) => gridModel.setSortBy(value)
|
|
52
|
+
},
|
|
53
|
+
owner: gridModel
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (persistGrouping) {
|
|
58
|
+
const persistWith = isObject(persistSort) ? persistSort : rootPersistWith;
|
|
59
|
+
PersistenceProvider.create({
|
|
60
|
+
persistOptions: {
|
|
61
|
+
path: `${path}.groupBy`,
|
|
62
|
+
...persistWith
|
|
63
|
+
},
|
|
64
|
+
target: {
|
|
65
|
+
getPersistableState: () => new PersistableState(gridModel.groupBy),
|
|
66
|
+
setPersistableState: ({value}) => gridModel.setGroupBy(value)
|
|
67
|
+
},
|
|
68
|
+
owner: gridModel
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -5,19 +5,12 @@
|
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
HoistModel,
|
|
10
|
-
managed,
|
|
11
|
-
PersistenceProvider,
|
|
12
|
-
PersistOptions,
|
|
13
|
-
PlainObject,
|
|
14
|
-
XH
|
|
15
|
-
} from '@xh/hoist/core';
|
|
8
|
+
import {HoistModel, PersistableState, PersistenceProvider, PersistOptions} from '@xh/hoist/core';
|
|
16
9
|
import {genDisplayName} from '@xh/hoist/data';
|
|
17
10
|
import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
|
|
18
11
|
import {executeIfFunction, throwIf} from '@xh/hoist/utils/js';
|
|
19
12
|
import {createObservableRef} from '@xh/hoist/utils/react';
|
|
20
|
-
import {
|
|
13
|
+
import {difference, isArray, isEmpty, isEqual, isObject, isString, keys, sortBy} from 'lodash';
|
|
21
14
|
|
|
22
15
|
export interface GroupingChooserConfig {
|
|
23
16
|
/**
|
|
@@ -62,11 +55,11 @@ export interface DimensionSpec {
|
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
export interface GroupingChooserPersistOptions extends PersistOptions {
|
|
65
|
-
/** True (default) to
|
|
66
|
-
persistValue?: boolean;
|
|
58
|
+
/** True (default) to include value or provide value-specific PersistOptions. */
|
|
59
|
+
persistValue?: boolean | PersistOptions;
|
|
67
60
|
|
|
68
|
-
/** True (default) to include favorites. */
|
|
69
|
-
persistFavorites?: boolean;
|
|
61
|
+
/** True (default) to include favorites or provide favorites-specific PersistOptions. */
|
|
62
|
+
persistFavorites?: boolean | PersistOptions;
|
|
70
63
|
}
|
|
71
64
|
|
|
72
65
|
export class GroupingChooserModel extends HoistModel {
|
|
@@ -76,9 +69,6 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
76
69
|
allowEmpty: boolean;
|
|
77
70
|
maxDepth: number;
|
|
78
71
|
commitOnChange: boolean;
|
|
79
|
-
|
|
80
|
-
@managed provider: PersistenceProvider = null;
|
|
81
|
-
persistValue: boolean = false;
|
|
82
72
|
persistFavorites: boolean = false;
|
|
83
73
|
|
|
84
74
|
// Implementation fields for Control
|
|
@@ -140,34 +130,10 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
140
130
|
throwIf(isEmpty(value) && !this.allowEmpty, 'Initial value cannot be empty.');
|
|
141
131
|
throwIf(!this.validateValue(value), 'Initial value is invalid.');
|
|
142
132
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
path: 'groupingChooser',
|
|
148
|
-
...persistWith
|
|
149
|
-
});
|
|
150
|
-
this.persistValue = persistWith.persistValue ?? true;
|
|
151
|
-
this.persistFavorites = persistWith.persistFavorites ?? true;
|
|
152
|
-
|
|
153
|
-
const state = cloneDeep(this.provider.read());
|
|
154
|
-
if (this.persistValue && state?.value && this.validateValue(state?.value)) {
|
|
155
|
-
value = state.value;
|
|
156
|
-
}
|
|
157
|
-
if (this.persistFavorites && state?.favorites) {
|
|
158
|
-
favorites = state.favorites;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
this.addReaction({
|
|
162
|
-
track: () => this.persistState,
|
|
163
|
-
run: state => this.provider.write(state)
|
|
164
|
-
});
|
|
165
|
-
} catch (e) {
|
|
166
|
-
this.logError(e);
|
|
167
|
-
XH.safeDestroy(this.provider);
|
|
168
|
-
this.provider = null;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
133
|
+
this.setValue(value);
|
|
134
|
+
this.setFavorites(favorites);
|
|
135
|
+
|
|
136
|
+
if (persistWith) this.initPersist(persistWith);
|
|
171
137
|
|
|
172
138
|
this.addReaction({
|
|
173
139
|
track: () => this.pendingValue,
|
|
@@ -175,9 +141,6 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
175
141
|
if (this.commitOnChange) this.setValue(this.pendingValue);
|
|
176
142
|
}
|
|
177
143
|
});
|
|
178
|
-
|
|
179
|
-
this.setValue(value);
|
|
180
|
-
this.setFavorites(favorites);
|
|
181
144
|
}
|
|
182
145
|
|
|
183
146
|
@action
|
|
@@ -320,19 +283,47 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
320
283
|
return this.favorites?.some(v => isEqual(v, value));
|
|
321
284
|
}
|
|
322
285
|
|
|
323
|
-
//-------------------------
|
|
324
|
-
// Persistence handling
|
|
325
|
-
//-------------------------
|
|
326
|
-
get persistState() {
|
|
327
|
-
const ret: PlainObject = {};
|
|
328
|
-
if (this.persistValue) ret.value = this.value;
|
|
329
|
-
if (this.persistFavorites) ret.favorites = this.favorites;
|
|
330
|
-
return ret;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
286
|
//------------------------
|
|
334
287
|
// Implementation
|
|
335
288
|
//------------------------
|
|
289
|
+
private initPersist({
|
|
290
|
+
persistValue = true,
|
|
291
|
+
persistFavorites = true,
|
|
292
|
+
path = 'groupingChooser',
|
|
293
|
+
...rootPersistWith
|
|
294
|
+
}: GroupingChooserPersistOptions) {
|
|
295
|
+
if (persistValue) {
|
|
296
|
+
const persistWith = isObject(persistValue) ? persistValue : rootPersistWith;
|
|
297
|
+
PersistenceProvider.create({
|
|
298
|
+
persistOptions: {
|
|
299
|
+
path: `${path}.value`,
|
|
300
|
+
...persistWith
|
|
301
|
+
},
|
|
302
|
+
target: {
|
|
303
|
+
getPersistableState: () => new PersistableState(this.value),
|
|
304
|
+
setPersistableState: ({value}) => this.setValue(value)
|
|
305
|
+
},
|
|
306
|
+
owner: this
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (persistFavorites) {
|
|
311
|
+
const persistWith = isObject(persistFavorites) ? persistFavorites : rootPersistWith,
|
|
312
|
+
provider = PersistenceProvider.create({
|
|
313
|
+
persistOptions: {
|
|
314
|
+
path: `${path}.favorites`,
|
|
315
|
+
...persistWith
|
|
316
|
+
},
|
|
317
|
+
target: {
|
|
318
|
+
getPersistableState: () => new PersistableState(this.favorites),
|
|
319
|
+
setPersistableState: ({value}) => this.setFavorites(value)
|
|
320
|
+
},
|
|
321
|
+
owner: this
|
|
322
|
+
});
|
|
323
|
+
if (provider) this.persistFavorites = true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
336
327
|
private normalizeDimensions(
|
|
337
328
|
dims: Array<DimensionSpec | string>
|
|
338
329
|
): Record<string, DimensionSpec> {
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import {
|
|
8
8
|
HoistModel,
|
|
9
9
|
managed,
|
|
10
|
+
Persistable,
|
|
11
|
+
PersistableState,
|
|
10
12
|
PersistenceProvider,
|
|
11
13
|
PersistOptions,
|
|
12
14
|
RefreshContextModel,
|
|
@@ -18,7 +20,7 @@ import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
|
18
20
|
import {wait} from '@xh/hoist/promise';
|
|
19
21
|
import {isOmitted} from '@xh/hoist/utils/impl';
|
|
20
22
|
import {ensureUniqueBy, throwIf} from '@xh/hoist/utils/js';
|
|
21
|
-
import {difference, find, findLast, isString,
|
|
23
|
+
import {difference, find, findLast, isString, without} from 'lodash';
|
|
22
24
|
import {ReactNode} from 'react';
|
|
23
25
|
import {TabConfig, TabModel} from './TabModel';
|
|
24
26
|
import {TabSwitcherProps} from './TabSwitcherProps';
|
|
@@ -85,7 +87,7 @@ export interface TabContainerConfig {
|
|
|
85
87
|
*
|
|
86
88
|
* Note: Routing is currently enabled for desktop applications only.
|
|
87
89
|
*/
|
|
88
|
-
export class TabContainerModel extends HoistModel {
|
|
90
|
+
export class TabContainerModel extends HoistModel implements Persistable<{activeTabId: string}> {
|
|
89
91
|
declare config: TabContainerConfig;
|
|
90
92
|
|
|
91
93
|
@managed
|
|
@@ -102,7 +104,6 @@ export class TabContainerModel extends HoistModel {
|
|
|
102
104
|
renderMode: RenderMode;
|
|
103
105
|
refreshMode: RefreshMode;
|
|
104
106
|
emptyText: ReactNode;
|
|
105
|
-
provider: PersistenceProvider;
|
|
106
107
|
|
|
107
108
|
@managed
|
|
108
109
|
refreshContextModel: RefreshContextModel;
|
|
@@ -156,7 +157,13 @@ export class TabContainerModel extends HoistModel {
|
|
|
156
157
|
|
|
157
158
|
this.forwardRouterToTab(this.activeTabId);
|
|
158
159
|
} else if (persistWith) {
|
|
159
|
-
|
|
160
|
+
PersistenceProvider.create({
|
|
161
|
+
persistOptions: {
|
|
162
|
+
path: 'tabContainer',
|
|
163
|
+
...persistWith
|
|
164
|
+
},
|
|
165
|
+
target: this
|
|
166
|
+
});
|
|
160
167
|
}
|
|
161
168
|
|
|
162
169
|
if (track) {
|
|
@@ -320,6 +327,17 @@ export class TabContainerModel extends HoistModel {
|
|
|
320
327
|
if (target) this.activateTab(target);
|
|
321
328
|
}
|
|
322
329
|
|
|
330
|
+
//-------------------------
|
|
331
|
+
// Persistable Interface
|
|
332
|
+
//-------------------------
|
|
333
|
+
getPersistableState(): PersistableState<{activeTabId: string}> {
|
|
334
|
+
return new PersistableState({activeTabId: this.activeTabId});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
setPersistableState(state: PersistableState<{activeTabId: string}>): void {
|
|
338
|
+
this.activateTab(state.value.activeTabId);
|
|
339
|
+
}
|
|
340
|
+
|
|
323
341
|
//-------------------------
|
|
324
342
|
// Implementation
|
|
325
343
|
//-------------------------
|
|
@@ -374,38 +392,6 @@ export class TabContainerModel extends HoistModel {
|
|
|
374
392
|
|
|
375
393
|
return null;
|
|
376
394
|
}
|
|
377
|
-
|
|
378
|
-
private setupStateProvider(persistWith) {
|
|
379
|
-
// Read state from provider -- fail gently
|
|
380
|
-
let state = null;
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
this.provider = PersistenceProvider.create({path: 'tabContainer', ...persistWith});
|
|
384
|
-
state = this.provider.read() || null;
|
|
385
|
-
} catch (e) {
|
|
386
|
-
this.logError(e);
|
|
387
|
-
XH.safeDestroy(this.provider);
|
|
388
|
-
this.provider = null;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
// Initialize state, or clear if state's activeTabId no longer exists
|
|
392
|
-
if (!isUndefined(state?.activeTabId)) {
|
|
393
|
-
const id = state.activeTabId;
|
|
394
|
-
if (this.findTab(id)) {
|
|
395
|
-
this.activateTab(id);
|
|
396
|
-
} else {
|
|
397
|
-
this.provider.clear();
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Attach to provider last
|
|
402
|
-
if (this.provider) {
|
|
403
|
-
this.addReaction({
|
|
404
|
-
track: () => this.activeTabId,
|
|
405
|
-
run: activeTabId => this.provider.write({activeTabId})
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
395
|
}
|
|
410
396
|
|
|
411
397
|
export interface AddTabOptions {
|
package/cmp/zoneGrid/Types.ts
CHANGED
|
@@ -38,10 +38,10 @@ export interface ZoneField {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface ZoneGridModelPersistOptions extends PersistOptions {
|
|
41
|
-
/** True to include mapping
|
|
42
|
-
|
|
43
|
-
/** True to include grouping
|
|
44
|
-
persistGrouping?: boolean;
|
|
45
|
-
/** True to include
|
|
46
|
-
persistSort?: boolean;
|
|
41
|
+
/** True (default) to include mapping state or provide mapping-specific PersistOptions. */
|
|
42
|
+
persistMappings?: boolean | PersistOptions;
|
|
43
|
+
/** True (default) to include grouping state or provide grouping-specific PersistOptions. */
|
|
44
|
+
persistGrouping?: boolean | PersistOptions;
|
|
45
|
+
/** True (default) to include sort state or provide sort-specific PersistOptions. */
|
|
46
|
+
persistSort?: boolean | PersistOptions;
|
|
47
47
|
}
|
|
@@ -56,7 +56,7 @@ import {action, bindable, makeObservable, observable} from '@xh/hoist/mobx';
|
|
|
56
56
|
import {executeIfFunction, throwIf, withDefault} from '@xh/hoist/utils/js';
|
|
57
57
|
import {castArray, find, forOwn, isEmpty, isFinite, isPlainObject, isString} from 'lodash';
|
|
58
58
|
import {ReactNode} from 'react';
|
|
59
|
-
import {
|
|
59
|
+
import {initPersist} from './impl/InitPersist';
|
|
60
60
|
import {ZoneMapperConfig, ZoneMapperModel} from './impl/ZoneMapperModel';
|
|
61
61
|
import {Zone, ZoneGridModelPersistOptions, ZoneLimit, ZoneMapping} from './Types';
|
|
62
62
|
|
|
@@ -315,7 +315,6 @@ export class ZoneGridModel extends HoistModel {
|
|
|
315
315
|
restoreDefaultsWarning: ReactNode;
|
|
316
316
|
|
|
317
317
|
private _defaultState; // initial state provided to ctor - powers restoreDefaults().
|
|
318
|
-
@managed persistenceModel: ZoneGridPersistenceModel;
|
|
319
318
|
|
|
320
319
|
constructor(config: ZoneGridConfig) {
|
|
321
320
|
super();
|
|
@@ -363,9 +362,7 @@ export class ZoneGridModel extends HoistModel {
|
|
|
363
362
|
this.setGroupBy(groupBy);
|
|
364
363
|
|
|
365
364
|
this.mapperModel = this.parseMapperModel(zoneMapperModel);
|
|
366
|
-
this
|
|
367
|
-
? new ZoneGridPersistenceModel(this, persistWith)
|
|
368
|
-
: null;
|
|
365
|
+
if (persistWith) initPersist(this, persistWith);
|
|
369
366
|
|
|
370
367
|
this.addReaction({
|
|
371
368
|
track: () => [this.leftColumnSpec, this.rightColumnSpec],
|
|
@@ -398,8 +395,6 @@ export class ZoneGridModel extends HoistModel {
|
|
|
398
395
|
this.setSortBy(sortBy);
|
|
399
396
|
this.setGroupBy(groupBy);
|
|
400
397
|
|
|
401
|
-
this.persistenceModel?.clear();
|
|
402
|
-
|
|
403
398
|
if (this.restoreDefaultsFn) {
|
|
404
399
|
await this.restoreDefaultsFn();
|
|
405
400
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
import {PersistableState, PersistenceProvider} from '@xh/hoist/core';
|
|
8
|
+
import {isObject} from 'lodash';
|
|
9
|
+
import {ZoneGridModel} from '../ZoneGridModel';
|
|
10
|
+
import {ZoneGridModelPersistOptions} from '../Types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initialize persistence for a {@link ZoneGridModel} by applying its `persistWith` config.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function initPersist(
|
|
17
|
+
zoneGridModel: ZoneGridModel,
|
|
18
|
+
{
|
|
19
|
+
persistMappings = true,
|
|
20
|
+
persistGrouping = true,
|
|
21
|
+
persistSort = true,
|
|
22
|
+
path = 'zoneGrid',
|
|
23
|
+
...rootPersistWith
|
|
24
|
+
}: ZoneGridModelPersistOptions
|
|
25
|
+
) {
|
|
26
|
+
if (persistMappings) {
|
|
27
|
+
const persistWith = isObject(persistMappings) ? persistMappings : rootPersistWith;
|
|
28
|
+
PersistenceProvider.create({
|
|
29
|
+
persistOptions: {
|
|
30
|
+
path: `${path}.mappings`,
|
|
31
|
+
...persistWith
|
|
32
|
+
},
|
|
33
|
+
target: {
|
|
34
|
+
getPersistableState: () => new PersistableState(zoneGridModel.mappings),
|
|
35
|
+
setPersistableState: ({value}) => zoneGridModel.setMappings(value)
|
|
36
|
+
},
|
|
37
|
+
owner: zoneGridModel
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (persistGrouping) {
|
|
42
|
+
const persistWith = isObject(persistGrouping) ? persistGrouping : rootPersistWith;
|
|
43
|
+
PersistenceProvider.create({
|
|
44
|
+
persistOptions: {
|
|
45
|
+
path: `${path}.groupBy`,
|
|
46
|
+
...persistWith
|
|
47
|
+
},
|
|
48
|
+
target: {
|
|
49
|
+
getPersistableState: () => new PersistableState(zoneGridModel.groupBy),
|
|
50
|
+
setPersistableState: ({value}) => zoneGridModel.setGroupBy(value)
|
|
51
|
+
},
|
|
52
|
+
owner: zoneGridModel
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (persistSort) {
|
|
57
|
+
const persistWith = isObject(persistSort) ? persistSort : rootPersistWith;
|
|
58
|
+
PersistenceProvider.create({
|
|
59
|
+
persistOptions: {
|
|
60
|
+
path: `${path}.sortBy`,
|
|
61
|
+
...persistWith
|
|
62
|
+
},
|
|
63
|
+
target: {
|
|
64
|
+
getPersistableState: () => new PersistableState(zoneGridModel.sortBy?.toString()),
|
|
65
|
+
setPersistableState: ({value}) => zoneGridModel.setSortBy(value)
|
|
66
|
+
},
|
|
67
|
+
owner: zoneGridModel
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
package/core/HoistBase.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {runInAction} from 'mobx';
|
|
8
|
+
import {XH, PersistenceProvider, PersistOptions, DebounceSpec, Some, PersistableState} from './';
|
|
8
9
|
import {
|
|
9
10
|
throwIf,
|
|
10
11
|
getOrCreate,
|
|
@@ -16,19 +17,16 @@ import {
|
|
|
16
17
|
withInfo
|
|
17
18
|
} from '@xh/hoist/utils/js';
|
|
18
19
|
import {
|
|
19
|
-
cloneDeep,
|
|
20
20
|
debounce as lodashDebounce,
|
|
21
21
|
isFunction,
|
|
22
22
|
isNil,
|
|
23
23
|
isNumber,
|
|
24
24
|
isPlainObject,
|
|
25
25
|
isString,
|
|
26
|
-
isUndefined,
|
|
27
26
|
upperFirst
|
|
28
27
|
} from 'lodash';
|
|
29
28
|
import {
|
|
30
29
|
action,
|
|
31
|
-
runInAction,
|
|
32
30
|
comparer,
|
|
33
31
|
autorun as mobxAutorun,
|
|
34
32
|
reaction as mobxReaction,
|
|
@@ -258,26 +256,20 @@ export abstract class HoistBase {
|
|
|
258
256
|
* @param options - options governing the persistence of this object. These will be applied
|
|
259
257
|
* on top of any default persistWith options defined on the instance itself.
|
|
260
258
|
*/
|
|
261
|
-
markPersist(property: string, options: PersistOptions = {}) {
|
|
259
|
+
markPersist(property: keyof this & string, options: PersistOptions = {}) {
|
|
262
260
|
// Read from and attach to Provider, failing gently
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
261
|
+
PersistenceProvider.create({
|
|
262
|
+
persistOptions: {
|
|
263
|
+
path: property,
|
|
264
|
+
...this.persistWith,
|
|
265
|
+
...options
|
|
266
|
+
},
|
|
267
|
+
owner: this,
|
|
268
|
+
target: {
|
|
269
|
+
getPersistableState: () => new PersistableState(this[property]),
|
|
270
|
+
setPersistableState: state => runInAction(() => (this[property] = state.value))
|
|
269
271
|
}
|
|
270
|
-
|
|
271
|
-
track: () => this[property],
|
|
272
|
-
run: data => provider.write(data)
|
|
273
|
-
});
|
|
274
|
-
} catch (e) {
|
|
275
|
-
this.logError(
|
|
276
|
-
`Failed to configure Persistence for '${property}'. Be sure to fully specify ` +
|
|
277
|
-
`'persistWith' on this object or in the method call`,
|
|
278
|
-
e
|
|
279
|
-
);
|
|
280
|
-
}
|
|
272
|
+
});
|
|
281
273
|
}
|
|
282
274
|
|
|
283
275
|
/** @returns true if this instance has been destroyed. */
|
|
@@ -4,10 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {cloneDeep, isUndefined} from 'lodash';
|
|
8
|
-
import {wait} from '../promise';
|
|
9
7
|
import {logError, throwIf} from '../utils/js';
|
|
10
|
-
import {HoistBaseClass, PersistenceProvider, PersistOptions} from './';
|
|
8
|
+
import {HoistBaseClass, PersistableState, PersistenceProvider, PersistOptions} from './';
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* Decorator to make a property "managed". Managed properties are designed to hold objects that
|
|
@@ -74,34 +72,34 @@ function createPersistDescriptor(
|
|
|
74
72
|
return descriptor;
|
|
75
73
|
}
|
|
76
74
|
const codeValue = descriptor.initializer;
|
|
75
|
+
let hasInitialized = false,
|
|
76
|
+
ret;
|
|
77
77
|
const initializer = function () {
|
|
78
|
-
|
|
78
|
+
// Initializer can be called multiple times when stacking decorators.
|
|
79
|
+
if (hasInitialized) return ret;
|
|
79
80
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const persistWith = {path: property, ...this.persistWith, ...options},
|
|
84
|
-
provider = this.markManaged(PersistenceProvider.create(persistWith));
|
|
85
|
-
providerState = cloneDeep(provider.read());
|
|
86
|
-
wait().then(() => {
|
|
87
|
-
this.addReaction({
|
|
88
|
-
track: () => this[property],
|
|
89
|
-
run: data => provider.write(data)
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
} catch (e) {
|
|
93
|
-
logError(
|
|
94
|
-
[
|
|
95
|
-
`Failed to configure Persistence for '${property}'. Be sure to fully specify ` +
|
|
96
|
-
`'persistWith' on this object or annotation`,
|
|
97
|
-
e
|
|
98
|
-
],
|
|
99
|
-
target
|
|
100
|
-
);
|
|
101
|
-
}
|
|
81
|
+
// codeValue undefined if no initial in-code value provided, otherwise call to get initial value.
|
|
82
|
+
ret = codeValue?.call(this);
|
|
102
83
|
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
const persistOptions = {path: property, ...this.persistWith, ...options};
|
|
85
|
+
PersistenceProvider.create({
|
|
86
|
+
persistOptions,
|
|
87
|
+
owner: this,
|
|
88
|
+
target: {
|
|
89
|
+
getPersistableState: () =>
|
|
90
|
+
new PersistableState(hasInitialized ? this[property] : ret),
|
|
91
|
+
setPersistableState: state => {
|
|
92
|
+
if (!hasInitialized) {
|
|
93
|
+
ret = state.value;
|
|
94
|
+
} else {
|
|
95
|
+
this[property] = state.value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
hasInitialized = true;
|
|
102
|
+
return ret;
|
|
105
103
|
};
|
|
106
104
|
return {...descriptor, initializer};
|
|
107
105
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {PersistenceProvider,
|
|
8
|
+
import {PersistenceProvider, PersistenceProviderConfig} from './';
|
|
9
9
|
import {throwIf} from '@xh/hoist/utils/js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -15,16 +15,17 @@ import {throwIf} from '@xh/hoist/utils/js';
|
|
|
15
15
|
* This provider allows applications to use the Persistence API to populate and read state from
|
|
16
16
|
* components without actually writing to any pre-defined storage.
|
|
17
17
|
*/
|
|
18
|
-
export class CustomProvider extends PersistenceProvider {
|
|
19
|
-
getData;
|
|
20
|
-
setData;
|
|
18
|
+
export class CustomProvider<S> extends PersistenceProvider<S> {
|
|
19
|
+
readonly getData;
|
|
20
|
+
readonly setData;
|
|
21
21
|
|
|
22
|
-
constructor(
|
|
22
|
+
constructor(cfg: PersistenceProviderConfig<S>) {
|
|
23
|
+
super(cfg);
|
|
24
|
+
const {getData, setData} = cfg.persistOptions;
|
|
23
25
|
throwIf(
|
|
24
26
|
!getData || !setData,
|
|
25
27
|
`CustomProvider requires a 'getData' and a 'setData' function.`
|
|
26
28
|
);
|
|
27
|
-
super(rest);
|
|
28
29
|
this.getData = getData;
|
|
29
30
|
this.setData = setData;
|
|
30
31
|
}
|
|
@@ -39,8 +40,4 @@ export class CustomProvider extends PersistenceProvider {
|
|
|
39
40
|
override writeRaw(data) {
|
|
40
41
|
this.setData(data);
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
override clearRaw() {
|
|
44
|
-
this.setData(null);
|
|
45
|
-
}
|
|
46
43
|
}
|
|
@@ -5,18 +5,20 @@
|
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import type {DashViewModel} from '@xh/hoist/desktop/cmp/dash'; // Import type only
|
|
9
9
|
import {throwIf} from '@xh/hoist/utils/js';
|
|
10
|
+
import {PersistenceProvider, PersistenceProviderConfig} from './';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* PersistenceProvider that stores state within a DashViewModel.
|
|
13
14
|
*/
|
|
14
|
-
export class DashViewProvider extends PersistenceProvider {
|
|
15
|
-
dashViewModel;
|
|
15
|
+
export class DashViewProvider<S> extends PersistenceProvider<S> {
|
|
16
|
+
readonly dashViewModel: DashViewModel;
|
|
16
17
|
|
|
17
|
-
constructor(
|
|
18
|
+
constructor(cfg: PersistenceProviderConfig<S>) {
|
|
19
|
+
super(cfg);
|
|
20
|
+
const {dashViewModel} = cfg.persistOptions;
|
|
18
21
|
throwIf(!dashViewModel, `DashViewProvider requires a 'dashViewModel'.`);
|
|
19
|
-
super(rest);
|
|
20
22
|
this.dashViewModel = dashViewModel;
|
|
21
23
|
}
|
|
22
24
|
|
|
@@ -29,10 +31,6 @@ export class DashViewProvider extends PersistenceProvider {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
override writeRaw(data) {
|
|
32
|
-
this.dashViewModel.
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
override clearRaw() {
|
|
36
|
-
return this.dashViewModel.setViewState(null);
|
|
34
|
+
this.dashViewModel.viewState = data;
|
|
37
35
|
}
|
|
38
36
|
}
|