@xh/hoist 71.0.0-SNAPSHOT.1733347475493 → 71.0.0-SNAPSHOT.1733376295239
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/build/types/cmp/viewmanager/ViewManagerModel.d.ts +11 -10
- package/build/types/cmp/viewmanager/ViewToBlobApi.d.ts +19 -0
- package/cmp/viewmanager/SaveAsDialogModel.ts +1 -1
- package/cmp/viewmanager/ViewManagerModel.ts +67 -109
- package/cmp/viewmanager/ViewToBlobApi.ts +110 -0
- package/desktop/cmp/viewmanager/dialog/EditForm.ts +2 -2
- package/desktop/cmp/viewmanager/dialog/ManageDialogModel.ts +2 -2
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -3,6 +3,7 @@ import type { ViewManagerProvider } from '@xh/hoist/core';
|
|
|
3
3
|
import { SaveAsDialogModel } from './SaveAsDialogModel';
|
|
4
4
|
import { ViewInfo } from './ViewInfo';
|
|
5
5
|
import { View } from './View';
|
|
6
|
+
import { ViewToBlobApi } from './ViewToBlobApi';
|
|
6
7
|
export interface ViewManagerConfig {
|
|
7
8
|
/**
|
|
8
9
|
* True (default) to allow user to opt in to automatically saving changes to their current view.
|
|
@@ -94,6 +95,7 @@ export declare class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
94
95
|
*/
|
|
95
96
|
static createAsync(config: ViewManagerConfig): Promise<ViewManagerModel>;
|
|
96
97
|
/** Immutable configuration for this model. */
|
|
98
|
+
persistWith: ViewManagerPersistOptions;
|
|
97
99
|
readonly viewType: string;
|
|
98
100
|
readonly typeDisplayName: string;
|
|
99
101
|
readonly globalDisplayName: string;
|
|
@@ -124,18 +126,22 @@ export declare class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
124
126
|
*/
|
|
125
127
|
saveTask: TaskObserver;
|
|
126
128
|
manageDialogOpen: boolean;
|
|
127
|
-
|
|
129
|
+
saveAsDialogModel: SaveAsDialogModel;
|
|
130
|
+
/** Unsaved changes on the current view.*/
|
|
128
131
|
private pendingValue;
|
|
129
|
-
private lastPushed;
|
|
130
132
|
/**
|
|
131
133
|
* Array of {@link ViewManagerProvider} instances bound to this model. Providers will
|
|
132
134
|
* push themselves onto this array when constructed with a reference to this model. Used to
|
|
133
135
|
* proactively push state to the target components when the model's selected `value` changes.
|
|
134
|
-
*
|
|
135
136
|
* @internal
|
|
136
137
|
*/
|
|
137
138
|
providers: ViewManagerProvider<any>[];
|
|
138
|
-
|
|
139
|
+
/**
|
|
140
|
+
* Data access for persisting views
|
|
141
|
+
* @internal
|
|
142
|
+
*/
|
|
143
|
+
api: ViewToBlobApi<T>;
|
|
144
|
+
private lastPushed;
|
|
139
145
|
get isValueDirty(): boolean;
|
|
140
146
|
get isViewSavable(): boolean;
|
|
141
147
|
get isViewAutoSavable(): boolean;
|
|
@@ -150,7 +156,6 @@ export declare class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
150
156
|
* initial load before binding to persistable components.
|
|
151
157
|
*/
|
|
152
158
|
private constructor();
|
|
153
|
-
private initAsync;
|
|
154
159
|
doLoadAsync(loadSpec: LoadSpec): Promise<void>;
|
|
155
160
|
selectViewAsync(info: ViewInfo): Promise<void>;
|
|
156
161
|
saveAsync(): Promise<void>;
|
|
@@ -165,12 +170,8 @@ export declare class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
165
170
|
openManageDialog(): void;
|
|
166
171
|
closeManageDialog(): void;
|
|
167
172
|
validateViewNameAsync(name: string, existing?: ViewInfo): Promise<string>;
|
|
168
|
-
|
|
169
|
-
updateViewAsync(view: ViewInfo, name: string, description: string, isGlobal: boolean): Promise<void>;
|
|
170
|
-
createViewAsync(name: string, description: string, value: PlainObject): Promise<View>;
|
|
173
|
+
private initAsync;
|
|
171
174
|
private loadViewAsync;
|
|
172
|
-
private fetchViewAsync;
|
|
173
|
-
private fetchViewInfosAsync;
|
|
174
175
|
private maybeAutoSaveAsync;
|
|
175
176
|
private setAsView;
|
|
176
177
|
private handleException;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PlainObject } from '@xh/hoist/core';
|
|
2
|
+
import { ViewInfo } from './ViewInfo';
|
|
3
|
+
import { View } from './View';
|
|
4
|
+
import { ViewManagerModel } from './ViewManagerModel';
|
|
5
|
+
/**
|
|
6
|
+
* Class for accessing and updating views using JSON Blobs Service.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare class ViewToBlobApi<T> {
|
|
11
|
+
private owner;
|
|
12
|
+
constructor(owner: ViewManagerModel<T>);
|
|
13
|
+
fetchViewInfosAsync(): Promise<ViewInfo[]>;
|
|
14
|
+
fetchViewAsync(info: ViewInfo): Promise<View<T>>;
|
|
15
|
+
createViewAsync(name: string, description: string, value: PlainObject): Promise<View<T>>;
|
|
16
|
+
updateViewInfoAsync(view: ViewInfo, name: string, description: string, isGlobal: boolean): Promise<View<T>>;
|
|
17
|
+
updateViewValueAsync(view: View<T>, value: Partial<T>): Promise<View<T>>;
|
|
18
|
+
deleteViewAsync(view: ViewInfo): Promise<void>;
|
|
19
|
+
}
|
|
@@ -81,7 +81,7 @@ export class SaveAsDialogModel extends HoistModel {
|
|
|
81
81
|
if (!isValid) return;
|
|
82
82
|
|
|
83
83
|
try {
|
|
84
|
-
const ret = await this.parent.createViewAsync(name, description, parent.getValue());
|
|
84
|
+
const ret = await this.parent.api.createViewAsync(name, description, parent.getValue());
|
|
85
85
|
this.close();
|
|
86
86
|
this.resolveOpen(ret);
|
|
87
87
|
} catch (e) {
|
|
@@ -30,6 +30,7 @@ import {ReactNode} from 'react';
|
|
|
30
30
|
import {SaveAsDialogModel} from './SaveAsDialogModel';
|
|
31
31
|
import {ViewInfo} from './ViewInfo';
|
|
32
32
|
import {View} from './View';
|
|
33
|
+
import {ViewToBlobApi} from './ViewToBlobApi';
|
|
33
34
|
|
|
34
35
|
export interface ViewManagerConfig {
|
|
35
36
|
/**
|
|
@@ -139,6 +140,7 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
/** Immutable configuration for this model. */
|
|
143
|
+
declare persistWith: ViewManagerPersistOptions;
|
|
142
144
|
readonly viewType: string;
|
|
143
145
|
readonly typeDisplayName: string;
|
|
144
146
|
readonly globalDisplayName: string;
|
|
@@ -174,25 +176,35 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
174
176
|
saveTask: TaskObserver;
|
|
175
177
|
|
|
176
178
|
@observable manageDialogOpen = false;
|
|
177
|
-
@managed
|
|
178
|
-
|
|
179
|
-
// Unsaved changes on the current view.
|
|
180
|
-
@observable.ref private pendingValue: PendingValue<T> = null;
|
|
179
|
+
@managed saveAsDialogModel: SaveAsDialogModel;
|
|
181
180
|
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
//-----------------------
|
|
182
|
+
// Private, internal state.
|
|
183
|
+
//-------------------------
|
|
184
|
+
/** Unsaved changes on the current view.*/
|
|
185
|
+
@observable.ref
|
|
186
|
+
private pendingValue: PendingValue<T> = null;
|
|
184
187
|
|
|
185
188
|
/**
|
|
186
189
|
* Array of {@link ViewManagerProvider} instances bound to this model. Providers will
|
|
187
190
|
* push themselves onto this array when constructed with a reference to this model. Used to
|
|
188
191
|
* proactively push state to the target components when the model's selected `value` changes.
|
|
189
|
-
*
|
|
190
192
|
* @internal
|
|
191
193
|
*/
|
|
192
194
|
providers: ViewManagerProvider<any>[] = [];
|
|
193
195
|
|
|
194
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Data access for persisting views
|
|
198
|
+
* @internal
|
|
199
|
+
*/
|
|
200
|
+
api: ViewToBlobApi<T>;
|
|
201
|
+
|
|
202
|
+
// Last time changes were pushed to linked persistence providers
|
|
203
|
+
private lastPushed: number = null;
|
|
195
204
|
|
|
205
|
+
//---------------
|
|
206
|
+
// Getters
|
|
207
|
+
//---------------
|
|
196
208
|
get isValueDirty(): boolean {
|
|
197
209
|
return !!this.pendingValue;
|
|
198
210
|
}
|
|
@@ -266,7 +278,6 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
266
278
|
this.enableAutoSave = enableAutoSave;
|
|
267
279
|
this.enableFavorites = enableFavorites;
|
|
268
280
|
this.settleTime = settleTime;
|
|
269
|
-
this.saveAsDialogModel = new SaveAsDialogModel(this);
|
|
270
281
|
this.initialViewSpec = initialViewSpec;
|
|
271
282
|
|
|
272
283
|
this.selectTask = TaskObserver.trackLast({
|
|
@@ -275,40 +286,15 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
275
286
|
this.saveTask = TaskObserver.trackLast({
|
|
276
287
|
message: `Saving ${this.typeDisplayName}...`
|
|
277
288
|
});
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
private async initAsync() {
|
|
281
|
-
try {
|
|
282
|
-
const views = await this.fetchViewInfosAsync();
|
|
283
|
-
runInAction(() => (this.views = views));
|
|
284
|
-
|
|
285
|
-
if (this.persistWith) {
|
|
286
|
-
this.initPersist(this.persistWith);
|
|
287
|
-
await when(() => !this.selectTask.isPending);
|
|
288
|
-
}
|
|
289
289
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
await this.loadViewAsync(this.initialViewSpec?.(views), this.pendingValue);
|
|
293
|
-
}
|
|
294
|
-
} catch (e) {
|
|
295
|
-
// Always ensure at least default view is installed.
|
|
296
|
-
if (!this.view) this.loadViewAsync(null, this.pendingValue);
|
|
297
|
-
|
|
298
|
-
this.handleException(e, {showAlert: false, logOnServer: true});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
this.addReaction({
|
|
302
|
-
track: () => [this.pendingValue, this.autoSave],
|
|
303
|
-
run: () => this.maybeAutoSaveAsync(),
|
|
304
|
-
debounce: 5 * SECONDS
|
|
305
|
-
});
|
|
290
|
+
this.saveAsDialogModel = new SaveAsDialogModel(this);
|
|
291
|
+
this.api = new ViewToBlobApi(this);
|
|
306
292
|
}
|
|
307
293
|
|
|
308
294
|
override async doLoadAsync(loadSpec: LoadSpec) {
|
|
309
295
|
try {
|
|
310
296
|
// 1) Update all view info
|
|
311
|
-
const views = await this.fetchViewInfosAsync();
|
|
297
|
+
const views = await this.api.fetchViewInfosAsync();
|
|
312
298
|
if (loadSpec.isStale) return;
|
|
313
299
|
runInAction(() => (this.views = views));
|
|
314
300
|
|
|
@@ -344,21 +330,20 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
344
330
|
this.logError('Unexpected conditions for call to save, skipping');
|
|
345
331
|
return;
|
|
346
332
|
}
|
|
347
|
-
const {pendingValue} = this
|
|
348
|
-
{info} = this.view;
|
|
333
|
+
const {pendingValue, view, api} = this;
|
|
349
334
|
try {
|
|
350
|
-
if (!(await this.maybeConfirmSaveAsync(info, pendingValue))) {
|
|
335
|
+
if (!(await this.maybeConfirmSaveAsync(view.info, pendingValue))) {
|
|
351
336
|
return;
|
|
352
337
|
}
|
|
353
|
-
const
|
|
354
|
-
.
|
|
338
|
+
const updated = await api
|
|
339
|
+
.updateViewValueAsync(view, pendingValue.value)
|
|
355
340
|
.linkTo(this.saveTask);
|
|
356
341
|
|
|
357
|
-
this.setAsView(
|
|
358
|
-
this.noteSuccess(`Saved ${info.typedName}`);
|
|
342
|
+
this.setAsView(updated);
|
|
343
|
+
this.noteSuccess(`Saved ${view.info.typedName}`);
|
|
359
344
|
} catch (e) {
|
|
360
345
|
this.handleException(e, {
|
|
361
|
-
message: `Failed to save ${info.typedName}. If this persists consider \`Save As...\`.`
|
|
346
|
+
message: `Failed to save ${view.info.typedName}. If this persists consider \`Save As...\`.`
|
|
362
347
|
});
|
|
363
348
|
}
|
|
364
349
|
this.refreshAsync();
|
|
@@ -451,46 +436,43 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
451
436
|
return null;
|
|
452
437
|
}
|
|
453
438
|
|
|
454
|
-
|
|
439
|
+
//------------------
|
|
440
|
+
// Implementation
|
|
441
|
+
//------------------
|
|
442
|
+
private async initAsync() {
|
|
455
443
|
try {
|
|
456
|
-
await
|
|
457
|
-
this.
|
|
458
|
-
} catch (e) {
|
|
459
|
-
throw XH.exception({message: `Unable to delete ${view.typedName}`, cause: e});
|
|
460
|
-
}
|
|
461
|
-
}
|
|
444
|
+
const views = await this.api.fetchViewInfosAsync();
|
|
445
|
+
runInAction(() => (this.views = views));
|
|
462
446
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
description: description?.trim(),
|
|
468
|
-
acl: isGlobal ? '*' : null
|
|
469
|
-
});
|
|
470
|
-
} catch (e) {
|
|
471
|
-
throw XH.exception({message: `Unable to update ${view.typedName}`, cause: e});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
447
|
+
if (this.persistWith) {
|
|
448
|
+
this.initPersist(this.persistWith);
|
|
449
|
+
await when(() => !this.selectTask.isPending);
|
|
450
|
+
}
|
|
474
451
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
name: name.trim(),
|
|
480
|
-
description: description?.trim(),
|
|
481
|
-
value
|
|
482
|
-
});
|
|
483
|
-
return View.fromBlob(blob, this);
|
|
452
|
+
// If the initial view not initialized from persistence, assign it.
|
|
453
|
+
if (!this.view) {
|
|
454
|
+
await this.loadViewAsync(this.initialViewSpec?.(views), this.pendingValue);
|
|
455
|
+
}
|
|
484
456
|
} catch (e) {
|
|
485
|
-
|
|
457
|
+
// Always ensure at least default view is installed.
|
|
458
|
+
if (!this.view) this.loadViewAsync(null, this.pendingValue);
|
|
459
|
+
|
|
460
|
+
this.handleException(e, {showAlert: false, logOnServer: true});
|
|
486
461
|
}
|
|
462
|
+
|
|
463
|
+
this.addReaction({
|
|
464
|
+
track: () => [this.pendingValue, this.autoSave],
|
|
465
|
+
run: () => this.maybeAutoSaveAsync(),
|
|
466
|
+
debounce: 5 * SECONDS
|
|
467
|
+
});
|
|
487
468
|
}
|
|
488
469
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
return this.
|
|
470
|
+
private async loadViewAsync(
|
|
471
|
+
info: ViewInfo,
|
|
472
|
+
pendingValue: PendingValue<T> = null
|
|
473
|
+
): Promise<void> {
|
|
474
|
+
return this.api
|
|
475
|
+
.fetchViewAsync(info)
|
|
494
476
|
.thenAction(latest => {
|
|
495
477
|
this.setAsView(latest, pendingValue?.token == info?.token ? pendingValue : null);
|
|
496
478
|
this.providers.forEach(it => it.pushStateToTarget());
|
|
@@ -499,44 +481,20 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
499
481
|
.linkTo(this.selectTask);
|
|
500
482
|
}
|
|
501
483
|
|
|
502
|
-
private async fetchViewAsync(info: ViewInfo): Promise<View<T>> {
|
|
503
|
-
if (!info) return View.createDefault();
|
|
504
|
-
try {
|
|
505
|
-
const blob = await XH.jsonBlobService.getAsync(info.token);
|
|
506
|
-
return View.fromBlob(blob, this);
|
|
507
|
-
} catch (e) {
|
|
508
|
-
throw XH.exception({message: `Unable to fetch ${info.typedName}`, cause: e});
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
private async fetchViewInfosAsync(): Promise<ViewInfo[]> {
|
|
513
|
-
try {
|
|
514
|
-
const blobs = await XH.jsonBlobService.listAsync({
|
|
515
|
-
type: this.viewType,
|
|
516
|
-
includeValue: false
|
|
517
|
-
});
|
|
518
|
-
return blobs.map(b => new ViewInfo(b, this));
|
|
519
|
-
} catch (e) {
|
|
520
|
-
throw XH.exception({
|
|
521
|
-
message: `Unable to fetch ${pluralize(this.typeDisplayName)}`,
|
|
522
|
-
cause: e
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
484
|
private async maybeAutoSaveAsync() {
|
|
528
|
-
const {pendingValue, isViewAutoSavable, view} = this;
|
|
485
|
+
const {pendingValue, isViewAutoSavable, view, api} = this;
|
|
529
486
|
if (isViewAutoSavable && pendingValue) {
|
|
530
487
|
try {
|
|
531
|
-
const
|
|
532
|
-
.
|
|
488
|
+
const updated = await api
|
|
489
|
+
.updateViewValueAsync(view, pendingValue.value)
|
|
533
490
|
.linkTo(this.saveTask);
|
|
534
|
-
|
|
491
|
+
|
|
492
|
+
this.setAsView(updated);
|
|
535
493
|
} catch (e) {
|
|
536
494
|
// TODO: How to alert but avoid for flaky or spam when user editing a deleted view
|
|
537
495
|
// Keep count and alert server and user once at count n?
|
|
538
496
|
XH.handleException(e, {
|
|
539
|
-
message: `Failing AutoSave for ${
|
|
497
|
+
message: `Failing AutoSave for ${view.info.typedName}`,
|
|
540
498
|
showAlert: false,
|
|
541
499
|
logOnServer: false
|
|
542
500
|
});
|
|
@@ -586,7 +544,7 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
586
544
|
|
|
587
545
|
private async maybeConfirmSaveAsync(info: ViewInfo, pendingValue: PendingValue<T>) {
|
|
588
546
|
// Get latest from server for reference
|
|
589
|
-
const latest = await this.fetchViewAsync(info),
|
|
547
|
+
const latest = await this.api.fetchViewAsync(info),
|
|
590
548
|
isGlobal = latest.isGlobal,
|
|
591
549
|
isStale = latest.lastUpdated > pendingValue.baseUpdated;
|
|
592
550
|
if (!isStale && !isGlobal) return true;
|
|
@@ -0,0 +1,110 @@
|
|
|
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 {PlainObject, XH} from '@xh/hoist/core';
|
|
9
|
+
import {pluralize} from '@xh/hoist/utils/js';
|
|
10
|
+
import {ViewInfo} from './ViewInfo';
|
|
11
|
+
import {View} from './View';
|
|
12
|
+
import {ViewManagerModel} from './ViewManagerModel';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Class for accessing and updating views using JSON Blobs Service.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export class ViewToBlobApi<T> {
|
|
20
|
+
private owner: ViewManagerModel<T>;
|
|
21
|
+
|
|
22
|
+
constructor(owner: ViewManagerModel<T>) {
|
|
23
|
+
this.owner = owner;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//---------------
|
|
27
|
+
// Load/search.
|
|
28
|
+
//---------------
|
|
29
|
+
async fetchViewInfosAsync(): Promise<ViewInfo[]> {
|
|
30
|
+
const {owner} = this;
|
|
31
|
+
try {
|
|
32
|
+
const blobs = await XH.jsonBlobService.listAsync({
|
|
33
|
+
type: owner.viewType,
|
|
34
|
+
includeValue: false
|
|
35
|
+
});
|
|
36
|
+
return blobs.map(b => new ViewInfo(b, owner));
|
|
37
|
+
} catch (e) {
|
|
38
|
+
throw XH.exception({
|
|
39
|
+
message: `Unable to fetch ${pluralize(owner.typeDisplayName)}`,
|
|
40
|
+
cause: e
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async fetchViewAsync(info: ViewInfo): Promise<View<T>> {
|
|
46
|
+
if (!info) return View.createDefault();
|
|
47
|
+
try {
|
|
48
|
+
const blob = await XH.jsonBlobService.getAsync(info.token);
|
|
49
|
+
return View.fromBlob(blob, this.owner);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
throw XH.exception({message: `Unable to fetch ${info.typedName}`, cause: e});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
//-----------------
|
|
56
|
+
// Crud
|
|
57
|
+
//-----------------
|
|
58
|
+
async createViewAsync(name: string, description: string, value: PlainObject): Promise<View<T>> {
|
|
59
|
+
const {owner} = this;
|
|
60
|
+
try {
|
|
61
|
+
const blob = await XH.jsonBlobService.createAsync({
|
|
62
|
+
type: owner.viewType,
|
|
63
|
+
name: name.trim(),
|
|
64
|
+
description: description?.trim(),
|
|
65
|
+
value
|
|
66
|
+
});
|
|
67
|
+
return View.fromBlob(blob, owner);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
throw XH.exception({message: `Unable to create ${owner.typeDisplayName}`, cause: e});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async updateViewInfoAsync(
|
|
74
|
+
view: ViewInfo,
|
|
75
|
+
name: string,
|
|
76
|
+
description: string,
|
|
77
|
+
isGlobal: boolean
|
|
78
|
+
): Promise<View<T>> {
|
|
79
|
+
try {
|
|
80
|
+
const blob = await XH.jsonBlobService.updateAsync(view.token, {
|
|
81
|
+
name: name.trim(),
|
|
82
|
+
description: description?.trim(),
|
|
83
|
+
acl: isGlobal ? '*' : null
|
|
84
|
+
});
|
|
85
|
+
return View.fromBlob(blob, this.owner);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
throw XH.exception({message: `Unable to update ${view.typedName}`, cause: e});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async updateViewValueAsync(view: View<T>, value: Partial<T>): Promise<View<T>> {
|
|
92
|
+
try {
|
|
93
|
+
const blob = await XH.jsonBlobService.updateAsync(view.token, {value});
|
|
94
|
+
return View.fromBlob(blob, this.owner);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
throw XH.exception({
|
|
97
|
+
message: `Unable to update value for ${view.info.typedName}`,
|
|
98
|
+
cause: e
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async deleteViewAsync(view: ViewInfo) {
|
|
104
|
+
try {
|
|
105
|
+
await XH.jsonBlobService.archiveAsync(view.token);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
throw XH.exception({message: `Unable to delete ${view.typedName}`, cause: e});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -15,7 +15,7 @@ import {formField} from '@xh/hoist/desktop/cmp/form';
|
|
|
15
15
|
import {select, textArea, textInput} from '@xh/hoist/desktop/cmp/input';
|
|
16
16
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
17
17
|
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
18
|
-
import {
|
|
18
|
+
import {fmtDateTime} from '@xh/hoist/format';
|
|
19
19
|
import {Icon} from '@xh/hoist/icon';
|
|
20
20
|
import {startCase} from 'lodash';
|
|
21
21
|
|
|
@@ -98,7 +98,7 @@ export const editForm = hoistCmp.factory({
|
|
|
98
98
|
filler(),
|
|
99
99
|
div({
|
|
100
100
|
className: 'xh-view-manager__manage-dialog__metadata',
|
|
101
|
-
item: `Last Updated: ${
|
|
101
|
+
item: `Last Updated: ${fmtDateTime(lastUpdated)} by ${lastUpdatedBy === XH.getUsername() ? 'you' : lastUpdatedBy}`
|
|
102
102
|
})
|
|
103
103
|
]
|
|
104
104
|
})
|
|
@@ -158,7 +158,7 @@ export class ManageDialogModel extends HoistModel {
|
|
|
158
158
|
) {
|
|
159
159
|
const {viewManagerModel} = this;
|
|
160
160
|
|
|
161
|
-
await viewManagerModel.
|
|
161
|
+
await viewManagerModel.api.updateViewInfoAsync(view, name, description, isGlobal);
|
|
162
162
|
await viewManagerModel.refreshAsync();
|
|
163
163
|
await this.refreshAsync();
|
|
164
164
|
|
|
@@ -200,7 +200,7 @@ export class ManageDialogModel extends HoistModel {
|
|
|
200
200
|
if (!confirmed) return;
|
|
201
201
|
|
|
202
202
|
for (const view of views) {
|
|
203
|
-
await viewManagerModel.deleteViewAsync(view);
|
|
203
|
+
await viewManagerModel.api.deleteViewAsync(view);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
await viewManagerModel.refreshAsync();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "71.0.0-SNAPSHOT.
|
|
3
|
+
"version": "71.0.0-SNAPSHOT.1733376295239",
|
|
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",
|