@xh/hoist 71.0.0-SNAPSHOT.1733262000771 → 71.0.0-SNAPSHOT.1733347475493

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.
Files changed (73) hide show
  1. package/CHANGELOG.md +8 -2
  2. package/appcontainer/AppContainerModel.ts +2 -1
  3. package/build/types/cmp/viewmanager/SaveAsDialogModel.d.ts +23 -0
  4. package/build/types/cmp/viewmanager/View.d.ts +28 -0
  5. package/build/types/cmp/viewmanager/ViewInfo.d.ts +30 -0
  6. package/build/types/cmp/viewmanager/ViewManagerModel.d.ts +185 -0
  7. package/build/types/cmp/viewmanager/index.d.ts +4 -0
  8. package/build/types/core/XH.d.ts +2 -1
  9. package/build/types/core/persist/PersistOptions.d.ts +3 -1
  10. package/build/types/core/persist/index.d.ts +6 -5
  11. package/build/types/core/persist/{CustomProvider.d.ts → provider/CustomProvider.d.ts} +1 -1
  12. package/build/types/core/persist/{DashViewProvider.d.ts → provider/DashViewProvider.d.ts} +2 -2
  13. package/build/types/core/persist/{LocalStorageProvider.d.ts → provider/LocalStorageProvider.d.ts} +1 -1
  14. package/build/types/core/persist/{PrefProvider.d.ts → provider/PrefProvider.d.ts} +1 -2
  15. package/build/types/core/persist/provider/SessionStorageProvider.d.ts +10 -0
  16. package/build/types/core/persist/{viewmanager → provider}/ViewManagerProvider.d.ts +3 -3
  17. package/build/types/desktop/cmp/viewmanager/ViewManager.d.ts +9 -10
  18. package/build/types/desktop/cmp/viewmanager/ViewMenu.d.ts +5 -0
  19. package/build/types/desktop/cmp/viewmanager/dialog/EditForm.d.ts +5 -0
  20. package/build/types/desktop/cmp/viewmanager/dialog/EditFormModel.d.ts +18 -0
  21. package/build/types/desktop/cmp/viewmanager/dialog/ManageDialog.d.ts +5 -0
  22. package/build/types/desktop/cmp/viewmanager/dialog/ManageDialogModel.d.ts +38 -0
  23. package/build/types/desktop/cmp/viewmanager/dialog/SaveAsDialog.d.ts +5 -0
  24. package/build/types/svc/JsonBlobService.d.ts +1 -1
  25. package/build/types/svc/index.d.ts +2 -1
  26. package/build/types/svc/storage/BaseStorageService.d.ts +21 -0
  27. package/build/types/svc/storage/LocalStorageService.d.ts +12 -0
  28. package/build/types/svc/storage/SessionStorageService.d.ts +12 -0
  29. package/cmp/viewmanager/SaveAsDialogModel.ts +97 -0
  30. package/cmp/viewmanager/View.ts +56 -0
  31. package/cmp/viewmanager/ViewInfo.ts +58 -0
  32. package/cmp/viewmanager/ViewManagerModel.ts +710 -0
  33. package/cmp/viewmanager/index.ts +4 -0
  34. package/core/XH.ts +2 -0
  35. package/core/persist/PersistOptions.ts +4 -1
  36. package/core/persist/PersistenceProvider.ts +5 -0
  37. package/core/persist/index.ts +6 -5
  38. package/core/persist/{CustomProvider.ts → provider/CustomProvider.ts} +1 -1
  39. package/core/persist/{DashViewProvider.ts → provider/DashViewProvider.ts} +1 -1
  40. package/core/persist/{LocalStorageProvider.ts → provider/LocalStorageProvider.ts} +1 -1
  41. package/core/persist/{PrefProvider.ts → provider/PrefProvider.ts} +2 -2
  42. package/core/persist/provider/SessionStorageProvider.ts +35 -0
  43. package/core/persist/{viewmanager → provider}/ViewManagerProvider.ts +5 -9
  44. package/desktop/cmp/viewmanager/ViewManager.ts +53 -229
  45. package/desktop/cmp/viewmanager/ViewMenu.ts +201 -0
  46. package/desktop/cmp/viewmanager/dialog/EditForm.ts +126 -0
  47. package/desktop/cmp/viewmanager/dialog/EditFormModel.ts +125 -0
  48. package/desktop/cmp/viewmanager/dialog/ManageDialog.ts +98 -0
  49. package/desktop/cmp/viewmanager/dialog/ManageDialogModel.ts +279 -0
  50. package/desktop/cmp/viewmanager/{impl/SaveDialog.ts → dialog/SaveAsDialog.ts} +20 -12
  51. package/package.json +1 -1
  52. package/svc/JsonBlobService.ts +1 -1
  53. package/svc/index.ts +2 -1
  54. package/svc/{LocalStorageService.ts → storage/BaseStorageService.ts} +13 -23
  55. package/svc/storage/LocalStorageService.ts +23 -0
  56. package/svc/storage/SessionStorageService.ts +23 -0
  57. package/tsconfig.tsbuildinfo +1 -1
  58. package/build/types/core/persist/viewmanager/Types.d.ts +0 -48
  59. package/build/types/core/persist/viewmanager/ViewManagerModel.d.ts +0 -145
  60. package/build/types/core/persist/viewmanager/impl/BuildViewTree.d.ts +0 -8
  61. package/build/types/core/persist/viewmanager/impl/ManageDialogModel.d.ts +0 -30
  62. package/build/types/core/persist/viewmanager/impl/SaveDialogModel.d.ts +0 -23
  63. package/build/types/core/persist/viewmanager/index.d.ts +0 -2
  64. package/build/types/desktop/cmp/viewmanager/impl/ManageDialog.d.ts +0 -6
  65. package/build/types/desktop/cmp/viewmanager/impl/SaveDialog.d.ts +0 -2
  66. package/build/types/svc/LocalStorageService.d.ts +0 -24
  67. package/core/persist/viewmanager/Types.ts +0 -53
  68. package/core/persist/viewmanager/ViewManagerModel.ts +0 -481
  69. package/core/persist/viewmanager/impl/BuildViewTree.ts +0 -68
  70. package/core/persist/viewmanager/impl/ManageDialogModel.ts +0 -276
  71. package/core/persist/viewmanager/impl/SaveDialogModel.ts +0 -112
  72. package/core/persist/viewmanager/index.ts +0 -2
  73. package/desktop/cmp/viewmanager/impl/ManageDialog.ts +0 -197
@@ -0,0 +1,279 @@
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
+
8
+ import {grid, GridAutosizeMode, GridModel} from '@xh/hoist/cmp/grid';
9
+ import {fragment, p, strong} from '@xh/hoist/cmp/layout';
10
+ import {TabContainerModel} from '@xh/hoist/cmp/tab';
11
+ import {HoistModel, LoadSpec, lookup, managed, TaskObserver, XH} from '@xh/hoist/core';
12
+ import {FilterTestFn} from '@xh/hoist/data';
13
+ import {computed} from 'mobx';
14
+ import {ReactNode} from 'react';
15
+ import {EditFormModel} from './EditFormModel';
16
+ import {Icon} from '@xh/hoist/icon';
17
+ import {bindable, makeObservable} from '@xh/hoist/mobx';
18
+ import {pluralize} from '@xh/hoist/utils/js';
19
+ import {ViewInfo, ViewManagerModel} from '@xh/hoist/cmp/viewmanager';
20
+ import {find, some, startCase} from 'lodash';
21
+
22
+ /**
23
+ * Backing model for ManageDialog
24
+ */
25
+ export class ManageDialogModel extends HoistModel {
26
+ @lookup(() => ViewManagerModel)
27
+ viewManagerModel: ViewManagerModel;
28
+
29
+ @managed privateGridModel: GridModel;
30
+ @managed globalGridModel: GridModel;
31
+ @managed editFormModel: EditFormModel;
32
+ @managed tabContainerModel: TabContainerModel;
33
+
34
+ @bindable filter: FilterTestFn;
35
+
36
+ readonly updateTask = TaskObserver.trackLast();
37
+
38
+ get loadTask(): TaskObserver {
39
+ return this.viewManagerModel.loadModel;
40
+ }
41
+
42
+ get gridModel(): GridModel {
43
+ return this.tabContainerModel.activeTabId == 'global'
44
+ ? this.globalGridModel
45
+ : this.privateGridModel;
46
+ }
47
+
48
+ @computed
49
+ get selectedView(): ViewInfo {
50
+ return this.gridModel.selectedRecord?.data.info;
51
+ }
52
+
53
+ @computed
54
+ get selectedViews(): ViewInfo[] {
55
+ return this.gridModel.selectedRecords.map(it => it.data.info) as ViewInfo[];
56
+ }
57
+
58
+ get canDelete(): boolean {
59
+ const {viewManagerModel, manageGlobal, selectedViews} = this,
60
+ {views, enableDefault} = viewManagerModel;
61
+
62
+ // Can't delete global views without role.
63
+ if (!manageGlobal && selectedViews.some(v => v.isGlobal)) return false;
64
+
65
+ // Can't delete all the views, unless default mode is enabled.
66
+ return enableDefault || views.length - selectedViews.length > 0;
67
+ }
68
+
69
+ get manageGlobal(): boolean {
70
+ return this.viewManagerModel.manageGlobal;
71
+ }
72
+
73
+ get typeDisplayName(): string {
74
+ return this.viewManagerModel.typeDisplayName;
75
+ }
76
+
77
+ get globalDisplayName(): string {
78
+ return this.viewManagerModel.globalDisplayName;
79
+ }
80
+
81
+ get enableFavorites(): boolean {
82
+ return this.viewManagerModel.enableFavorites;
83
+ }
84
+
85
+ constructor() {
86
+ super();
87
+ makeObservable(this);
88
+ }
89
+
90
+ close() {
91
+ this.viewManagerModel.closeManageDialog();
92
+ }
93
+
94
+ override onLinked() {
95
+ super.onLinked();
96
+
97
+ this.privateGridModel = this.createGridModel('personal');
98
+ this.globalGridModel = this.createGridModel(this.globalDisplayName);
99
+ this.tabContainerModel = this.createTabContainerModel();
100
+ this.editFormModel = new EditFormModel(this);
101
+
102
+ const {privateGridModel, globalGridModel, editFormModel} = this;
103
+ this.addReaction(
104
+ {
105
+ track: () => this.selectedView,
106
+ run: r => editFormModel.setView(r)
107
+ },
108
+ {
109
+ track: () => this.filter,
110
+ run: f => {
111
+ privateGridModel.store.setFilter(f);
112
+ globalGridModel.store.setFilter(f);
113
+ },
114
+ fireImmediately: true
115
+ },
116
+ {
117
+ track: () => privateGridModel.selectedRecords,
118
+ run: recs => {
119
+ if (recs.length) globalGridModel.clearSelection();
120
+ }
121
+ },
122
+ {
123
+ track: () => globalGridModel.selectedRecords,
124
+ run: recs => {
125
+ if (recs.length) privateGridModel.clearSelection();
126
+ }
127
+ }
128
+ );
129
+ }
130
+
131
+ override async doLoadAsync(loadSpec: LoadSpec) {
132
+ const {view, globalViews, privateViews} = this.viewManagerModel;
133
+ this.globalGridModel.loadData(globalViews);
134
+ this.privateGridModel.loadData(privateViews);
135
+ if (!loadSpec.isRefresh && !view.isDefault) {
136
+ await this.selectViewAsync(view.info);
137
+ }
138
+ }
139
+
140
+ async deleteAsync(views: ViewInfo[]) {
141
+ return this.doDeleteAsync(views).linkTo(this.updateTask).catchDefault();
142
+ }
143
+
144
+ async updateAsync(view: ViewInfo, name: string, description: string, isGlobal: boolean) {
145
+ return this.doUpdateAsync(view, name, description, isGlobal)
146
+ .linkTo(this.updateTask)
147
+ .catchDefault();
148
+ }
149
+
150
+ //------------------------
151
+ // Implementation
152
+ //------------------------
153
+ private async doUpdateAsync(
154
+ view: ViewInfo,
155
+ name: string,
156
+ description: string,
157
+ isGlobal: boolean
158
+ ) {
159
+ const {viewManagerModel} = this;
160
+
161
+ await viewManagerModel.updateViewAsync(view, name, description, isGlobal);
162
+ await viewManagerModel.refreshAsync();
163
+ await this.refreshAsync();
164
+
165
+ // reselect the updated copy of this view -- it may have moved.
166
+ await this.selectViewAsync(find(viewManagerModel.views, {token: view.token}));
167
+ }
168
+
169
+ private async doDeleteAsync(views: ViewInfo[]) {
170
+ const {viewManagerModel, typeDisplayName} = this,
171
+ {enableDefault} = viewManagerModel,
172
+ count = views.length;
173
+
174
+ if (!count) return;
175
+
176
+ if (viewManagerModel.views.length === count && !enableDefault) {
177
+ throw XH.exception({
178
+ message: `You cannot delete all ${pluralize(typeDisplayName)}.`,
179
+ isRoutine: true
180
+ });
181
+ }
182
+
183
+ const confirmStr = count > 1 ? pluralize(typeDisplayName, count, true) : views[0].typedName;
184
+ const msgs: ReactNode[] = [`Are you sure you want to delete ${confirmStr}?`];
185
+ if (some(views, 'isGlobal')) {
186
+ count > 1
187
+ ? msgs.push(strong('These global views will no longer be available to ALL users.'))
188
+ : msgs.push(strong('This global view will no longer be available to ALL users.'));
189
+ }
190
+
191
+ const confirmed = await XH.confirm({
192
+ message: fragment(msgs.map(m => p(m))),
193
+ confirmProps: {
194
+ text: `Yes, delete ${pluralize(typeDisplayName, count)}`,
195
+ outlined: true,
196
+ autoFocus: false,
197
+ intent: 'danger'
198
+ }
199
+ });
200
+ if (!confirmed) return;
201
+
202
+ for (const view of views) {
203
+ await viewManagerModel.deleteViewAsync(view);
204
+ }
205
+
206
+ await viewManagerModel.refreshAsync();
207
+ await this.refreshAsync();
208
+ }
209
+
210
+ async selectViewAsync(view: ViewInfo) {
211
+ this.tabContainerModel.activateTab(view.isGlobal ? 'global' : 'private');
212
+ await this.gridModel.selectAsync(view.token);
213
+ }
214
+
215
+ private createGridModel(name: string): GridModel {
216
+ return new GridModel({
217
+ emptyText: `No ${name} ${pluralize(this.typeDisplayName)} found...`,
218
+ sortBy: 'name',
219
+ hideHeaders: true,
220
+ showGroupRowCounts: false,
221
+ selModel: 'multiple',
222
+ contextMenu: null,
223
+ sizingMode: 'standard',
224
+ store: {
225
+ idSpec: 'token',
226
+ processRawData: v => ({name: v.name, isFavorite: v.isFavorite, info: v}),
227
+ fields: [
228
+ {name: 'name', type: 'string'},
229
+ {name: 'isFavorite', type: 'bool'},
230
+ {name: 'info', type: 'auto'}
231
+ ]
232
+ },
233
+ autosizeOptions: {mode: GridAutosizeMode.DISABLED},
234
+ columns: [
235
+ {field: 'name', flex: true},
236
+ {
237
+ colId: 'isFavorite',
238
+ field: 'info',
239
+ omit: !this.enableFavorites,
240
+ width: 40,
241
+ align: 'center',
242
+ headerName: Icon.favorite(),
243
+ highlightOnChange: true,
244
+ renderer: v => {
245
+ const {isFavorite} = v;
246
+ return Icon.favorite({
247
+ prefix: isFavorite ? 'fas' : 'fal',
248
+ className: isFavorite ? 'xh-yellow' : 'xh-text-color-muted'
249
+ });
250
+ }
251
+ }
252
+ ],
253
+ onCellClicked: ({colDef, data: record, api}) => {
254
+ if (colDef.colId === 'isFavorite') {
255
+ this.viewManagerModel.toggleFavorite(record.id);
256
+ api.redrawRows();
257
+ }
258
+ }
259
+ });
260
+ }
261
+
262
+ private createTabContainerModel(): TabContainerModel {
263
+ const pluralType = startCase(pluralize(this.typeDisplayName));
264
+ return new TabContainerModel({
265
+ tabs: [
266
+ {
267
+ id: 'private',
268
+ title: `My ${pluralType}`,
269
+ content: grid({model: this.privateGridModel})
270
+ },
271
+ {
272
+ id: 'global',
273
+ title: `${startCase(this.globalDisplayName)} ${pluralType}`,
274
+ content: grid({model: this.globalGridModel})
275
+ }
276
+ ]
277
+ });
278
+ }
279
+ }
@@ -1,26 +1,35 @@
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
+
1
8
  import {form} from '@xh/hoist/cmp/form';
2
9
  import {filler, vframe} from '@xh/hoist/cmp/layout';
3
10
  import {hoistCmp, uses} from '@xh/hoist/core';
4
- import {SaveDialogModel} from '@xh/hoist/core/persist/viewmanager/impl/SaveDialogModel';
11
+ import {SaveAsDialogModel} from '@xh/hoist/cmp/viewmanager/';
5
12
  import {button} from '@xh/hoist/desktop/cmp/button';
6
13
  import {formField} from '@xh/hoist/desktop/cmp/form';
7
14
  import {textArea, textInput} from '@xh/hoist/desktop/cmp/input';
8
15
  import {panel} from '@xh/hoist/desktop/cmp/panel';
9
16
  import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
10
- import {Icon} from '@xh/hoist/icon';
11
17
  import {dialog} from '@xh/hoist/kit/blueprint';
18
+ import {startCase} from 'lodash';
12
19
 
13
- export const saveDialog = hoistCmp.factory<SaveDialogModel>({
20
+ /**
21
+ * Default Save As dialog used by ViewManager.
22
+ */
23
+ export const saveAsDialog = hoistCmp.factory<SaveAsDialogModel>({
14
24
  displayName: 'SaveDialog',
15
25
  className: 'xh-view-manager__save-dialog',
16
- model: uses(SaveDialogModel),
26
+ model: uses(SaveAsDialogModel),
17
27
 
18
28
  render({model, className}) {
19
29
  if (!model.isOpen) return null;
20
30
 
21
31
  return dialog({
22
32
  title: `Save as...`,
23
- icon: Icon.copy(),
24
33
  className,
25
34
  isOpen: true,
26
35
  style: {width: 500},
@@ -31,7 +40,7 @@ export const saveDialog = hoistCmp.factory<SaveDialogModel>({
31
40
  }
32
41
  });
33
42
 
34
- const formPanel = hoistCmp.factory<SaveDialogModel>({
43
+ const formPanel = hoistCmp.factory<SaveAsDialogModel>({
35
44
  render({model}) {
36
45
  return panel({
37
46
  item: form({
@@ -62,14 +71,14 @@ const formPanel = hoistCmp.factory<SaveDialogModel>({
62
71
  })
63
72
  }),
64
73
  bbar: bbar(),
65
- mask: model.saveTask
74
+ mask: model.parent.saveTask
66
75
  });
67
76
  }
68
77
  });
69
78
 
70
- const bbar = hoistCmp.factory<SaveDialogModel>({
79
+ const bbar = hoistCmp.factory<SaveAsDialogModel>({
71
80
  render({model}) {
72
- const {formModel, DisplayName} = model;
81
+ const {typeDisplayName} = model;
73
82
  return toolbar(
74
83
  filler(),
75
84
  button({
@@ -77,11 +86,10 @@ const bbar = hoistCmp.factory<SaveDialogModel>({
77
86
  onClick: () => model.cancel()
78
87
  }),
79
88
  button({
80
- text: `Save as new ${DisplayName}`,
81
- icon: Icon.copy(),
89
+ text: `Save as new ${startCase(typeDisplayName)}`,
82
90
  outlined: true,
83
91
  intent: 'success',
84
- disabled: !formModel.isValid,
92
+ disabled: !model.formModel.isValid,
85
93
  onClick: () => model.saveAsAsync()
86
94
  })
87
95
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "71.0.0-SNAPSHOT.1733262000771",
3
+ "version": "71.0.0-SNAPSHOT.1733347475493",
4
4
  "description": "Hoist add-on for building and deploying React Applications.",
5
5
  "repository": "github:xh/hoist-react",
6
6
  "homepage": "https://xh.io",
@@ -9,7 +9,7 @@ import {pickBy} from 'lodash';
9
9
 
10
10
  export interface JsonBlob {
11
11
  /** Either null for private blobs or special token "*" for globally shared blobs. */
12
- acl: string;
12
+ acl: '*';
13
13
  /** True if this blob has been archived (soft-deleted). */
14
14
  archived: boolean;
15
15
  /** Timestamp indicating when this blob was archived, or special value `0` if not archived. */
package/svc/index.ts CHANGED
@@ -16,7 +16,8 @@ export * from './IdentityService';
16
16
  export * from './IdleService';
17
17
  export * from './InspectorService';
18
18
  export * from './JsonBlobService';
19
- export * from './LocalStorageService';
20
19
  export * from './PrefService';
21
20
  export * from './TrackService';
22
21
  export * from './WebSocketService';
22
+ export * from './storage/LocalStorageService';
23
+ export * from './storage/SessionStorageService';
@@ -6,26 +6,22 @@
6
6
  */
7
7
  import {HoistService, XH} from '@xh/hoist/core';
8
8
  import {throwIf} from '@xh/hoist/utils/js';
9
- import store from 'store2';
9
+ import {StoreType} from 'store2';
10
10
 
11
11
  /**
12
- * Service to provide simple key/value access to browser local storage, appropriately namespaced
13
- * by application code and username.
12
+ * Service to provide simple key/value access to browser local/session storage, appropriately
13
+ * namespaced by application code and username.
14
14
  *
15
- * In the unexpected case that local storage is not available, will provide a transient in-memory
15
+ * In the unexpected case that the core apis are not available, will provide a transient in-memory
16
16
  * storage to support its operations and API.
17
- *
18
- * Relied upon by Hoist features such as local preference values and grid state.
19
17
  */
20
- export class LocalStorageService extends HoistService {
21
- static instance: LocalStorageService;
22
-
18
+ export abstract class BaseStorageService extends HoistService {
23
19
  constructor() {
24
20
  super();
25
21
  if (this.isFake) {
26
22
  XH.handleException(
27
23
  XH.exception(
28
- 'Local Storage is not supported in this browser. Transient in-memory storage ' +
24
+ 'Requested Storage is not supported in this browser. Transient in-memory storage ' +
29
25
  'will be used as a fallback. All data stored will be lost when page is closed.'
30
26
  ),
31
27
  {showAlert: false}
@@ -34,7 +30,7 @@ export class LocalStorageService extends HoistService {
34
30
  }
35
31
 
36
32
  get(key: string, defaultValue?: any): any {
37
- const storage = this.getInstance(),
33
+ const storage = this.storeInstance,
38
34
  val = storage.get(key, defaultValue);
39
35
 
40
36
  throwIf(val === undefined, `Key '${key}' not found`);
@@ -42,7 +38,7 @@ export class LocalStorageService extends HoistService {
42
38
  }
43
39
 
44
40
  set(key: string, value: any) {
45
- this.getInstance().set(key, value, true);
41
+ this.storeInstance.set(key, value, true);
46
42
  }
47
43
 
48
44
  apply(key: string, newProps: object) {
@@ -53,7 +49,7 @@ export class LocalStorageService extends HoistService {
53
49
  }
54
50
 
55
51
  remove(key: string) {
56
- this.getInstance().remove(key);
52
+ this.storeInstance.remove(key);
57
53
  }
58
54
 
59
55
  removeIf(predicateFn: (s: string) => boolean) {
@@ -63,25 +59,19 @@ export class LocalStorageService extends HoistService {
63
59
  }
64
60
 
65
61
  clear() {
66
- this.getInstance().clear();
62
+ this.storeInstance().clear();
67
63
  }
68
64
 
69
65
  keys(): string[] {
70
- return this.getInstance().keys();
66
+ return this.storeInstance.keys();
71
67
  }
72
68
 
73
69
  get isFake(): boolean {
74
- return store.isFake();
70
+ return this.storeInstance.isFake();
75
71
  }
76
72
 
77
73
  //------------------
78
74
  // Implementation
79
75
  //------------------
80
- private getInstance() {
81
- return store.namespace(this.getNamespace());
82
- }
83
-
84
- private getNamespace() {
85
- return `${XH.appCode}.${XH.getUsername()}`;
86
- }
76
+ protected abstract get storeInstance(): StoreType;
87
77
  }
@@ -0,0 +1,23 @@
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 {XH} from '@xh/hoist/core';
8
+ import {BaseStorageService} from '@xh/hoist/svc/storage/BaseStorageService';
9
+ import store, {StoreType} from 'store2';
10
+
11
+ /**
12
+ * Service to provide simple key/value access to browser local storage, appropriately namespaced
13
+ * by application code and username.
14
+ *
15
+ * Relied upon by Hoist persistence mechanisms when using key 'localStorageKey`
16
+ */
17
+ export class LocalStorageService extends BaseStorageService {
18
+ static instance: LocalStorageService;
19
+
20
+ protected get storeInstance(): StoreType {
21
+ return store.local.namespace(`${XH.appCode}.${XH.getUsername()}`);
22
+ }
23
+ }
@@ -0,0 +1,23 @@
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 {XH} from '@xh/hoist/core';
8
+ import {BaseStorageService} from '@xh/hoist/svc/storage/BaseStorageService';
9
+ import store, {StoreType} from 'store2';
10
+
11
+ /**
12
+ * Service to provide simple key/value access to browser session storage, appropriately namespaced
13
+ * by application code and username.
14
+ *
15
+ * Relied upon by Hoist persistence mechanisms when using key 'sessionStorageKey`
16
+ */
17
+ export class SessionStorageService extends BaseStorageService {
18
+ static instance: SessionStorageService;
19
+
20
+ protected get storeInstance(): StoreType {
21
+ return store.session.namespace(`${XH.appCode}.${XH.getUsername()}`);
22
+ }
23
+ }