@xh/hoist 80.0.0-SNAPSHOT.1767799665209 → 80.0.0-SNAPSHOT.1767974090726
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 +13 -4
- package/admin/tabs/cluster/instances/services/DetailsPanel.ts +3 -3
- package/admin/tabs/cluster/instances/services/ServiceModel.ts +2 -2
- package/appcontainer/AppContainerModel.ts +5 -5
- package/appcontainer/AppStateModel.ts +1 -1
- package/appcontainer/FeedbackDialogModel.ts +3 -5
- package/build/types/appcontainer/AppContainerModel.d.ts +2 -2
- package/build/types/core/XH.d.ts +2 -1
- package/cmp/viewmanager/ViewManagerModel.ts +2 -2
- package/core/XH.ts +12 -4
- package/desktop/appcontainer/AppContainer.ts +1 -1
- package/desktop/appcontainer/LoginPanel.ts +2 -2
- package/desktop/cmp/viewmanager/ViewManager.ts +2 -2
- package/mobile/appcontainer/AppContainer.ts +1 -1
- package/mobile/appcontainer/LoginPanel.ts +2 -2
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## 80.0.0-SNAPSHOT - unreleased
|
|
4
4
|
|
|
5
|
+
### 💥 Breaking Changes
|
|
6
|
+
|
|
7
|
+
* Completed the refactoring away from `loadModel` to `loadObserver` started in v79:
|
|
8
|
+
* Renamed `XH.appLoadModel` to `XH.appLoadObserver`. The prior getter remains as an alias but is
|
|
9
|
+
deprecated and scheduled for removal in v82.
|
|
10
|
+
* Renamed `AppContainerModel.loadModel` to `loadObserver`. This is primarily an internal model,
|
|
11
|
+
so there is no deprecated alias. Any app usages should swap to `XH.appLoadObserver`.
|
|
12
|
+
* Removed additional references to deprecated `loadModel` within Hoist itself.
|
|
13
|
+
|
|
5
14
|
## 79.0.0 - 2026-01-05
|
|
6
15
|
|
|
7
16
|
### 💥 Breaking Changes
|
|
@@ -69,8 +78,8 @@ this release, but is not strictly required.
|
|
|
69
78
|
|
|
70
79
|
### 📚 Libraries
|
|
71
80
|
|
|
72
|
-
* @blueprintjs/core: `5.10
|
|
73
|
-
* @blueprintjs/datetime: `5.3
|
|
81
|
+
* @blueprintjs/core: `5.10 → 6.3`
|
|
82
|
+
* @blueprintjs/datetime: `5.3 → 6.0`
|
|
74
83
|
* react-grid-layout `1.5 → 2.1`
|
|
75
84
|
|
|
76
85
|
## 78.1.4 - 2025-12-05
|
|
@@ -856,8 +865,8 @@ build. That said, we *strongly* recommend taking these same changes into your ap
|
|
|
856
865
|
### 📚 Libraries
|
|
857
866
|
|
|
858
867
|
* @azure/msal-browser `3.17 → 3.23`
|
|
859
|
-
* mobx `6.9
|
|
860
|
-
* mobx-react-lite `3.4
|
|
868
|
+
* mobx `6.9 → 6.13`,
|
|
869
|
+
* mobx-react-lite `3.4 → 4.0`,
|
|
861
870
|
|
|
862
871
|
## 67.0.0 - 2024-09-03
|
|
863
872
|
|
|
@@ -35,9 +35,9 @@ export const detailsPanel = hoistCmp.factory({
|
|
|
35
35
|
|
|
36
36
|
const stats = hoistCmp.factory<DetailsModel>({
|
|
37
37
|
render({model}) {
|
|
38
|
-
const {stats, lastLoadException,
|
|
38
|
+
const {stats, lastLoadException, loadObserver} = model;
|
|
39
39
|
|
|
40
|
-
if (!
|
|
40
|
+
if (!loadObserver.isPending && lastLoadException) {
|
|
41
41
|
return errorMessage({
|
|
42
42
|
error: lastLoadException,
|
|
43
43
|
detailsFn: e => XH.exceptionHandler.showExceptionDetails(e)
|
|
@@ -46,7 +46,7 @@ const stats = hoistCmp.factory<DetailsModel>({
|
|
|
46
46
|
|
|
47
47
|
return isEmpty(stats)
|
|
48
48
|
? placeholder(
|
|
49
|
-
...(
|
|
49
|
+
...(loadObserver.isPending
|
|
50
50
|
? []
|
|
51
51
|
: [Icon.questionCircle(), 'This service does not report any admin stats.'])
|
|
52
52
|
)
|
|
@@ -91,7 +91,7 @@ export class ServiceModel extends BaseInstanceModel {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
async clearCachesAsync(entireCluster: boolean) {
|
|
94
|
-
const {gridModel, instanceName,
|
|
94
|
+
const {gridModel, instanceName, loadObserver} = this,
|
|
95
95
|
{selectedRecords} = gridModel;
|
|
96
96
|
|
|
97
97
|
if (isEmpty(selectedRecords)) return;
|
|
@@ -125,7 +125,7 @@ export class ServiceModel extends BaseInstanceModel {
|
|
|
125
125
|
instance: entireCluster ? null : instanceName,
|
|
126
126
|
names: selectedRecords.map(it => it.data.name)
|
|
127
127
|
}
|
|
128
|
-
}).linkTo(
|
|
128
|
+
}).linkTo(loadObserver);
|
|
129
129
|
await this.refreshAsync();
|
|
130
130
|
XH.successToast('Service caches cleared.');
|
|
131
131
|
} catch (e) {
|
|
@@ -76,7 +76,7 @@ export class AppContainerModel extends HoistModel {
|
|
|
76
76
|
//------------
|
|
77
77
|
// Sub-models
|
|
78
78
|
//------------
|
|
79
|
-
@managed
|
|
79
|
+
@managed appLoadObserver = TaskObserver.trackAll();
|
|
80
80
|
@managed appStateModel = new AppStateModel();
|
|
81
81
|
@managed pageStateModel = new PageStateModel();
|
|
82
82
|
@managed routerModel = new RouterModel();
|
|
@@ -250,7 +250,7 @@ export class AppContainerModel extends HoistModel {
|
|
|
250
250
|
|
|
251
251
|
// init all models other than Router
|
|
252
252
|
const models = [
|
|
253
|
-
this.
|
|
253
|
+
this.appLoadObserver,
|
|
254
254
|
this.appStateModel,
|
|
255
255
|
this.pageStateModel,
|
|
256
256
|
this.routerModel,
|
|
@@ -271,7 +271,7 @@ export class AppContainerModel extends HoistModel {
|
|
|
271
271
|
];
|
|
272
272
|
models.forEach((m: any) => m.init?.());
|
|
273
273
|
|
|
274
|
-
this.
|
|
274
|
+
this.bindInitSequenceToAppLoadObserver();
|
|
275
275
|
|
|
276
276
|
this.setDocTitle();
|
|
277
277
|
|
|
@@ -359,10 +359,10 @@ export class AppContainerModel extends HoistModel {
|
|
|
359
359
|
this.appStateModel.setAppState(nextState);
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
private
|
|
362
|
+
private bindInitSequenceToAppLoadObserver() {
|
|
363
363
|
const terminalStates: AppState[] = ['RUNNING', 'SUSPENDED', 'LOAD_FAILED', 'ACCESS_DENIED'],
|
|
364
364
|
loadingPromise = mobxWhen(() => terminalStates.includes(this.appStateModel.state));
|
|
365
|
-
loadingPromise.linkTo(this.
|
|
365
|
+
loadingPromise.linkTo(this.appLoadObserver);
|
|
366
366
|
}
|
|
367
367
|
|
|
368
368
|
private setViewportContent(content: string) {
|
|
@@ -57,7 +57,7 @@ export class AppStateModel extends HoistModel {
|
|
|
57
57
|
this.setAppState('SUSPENDED');
|
|
58
58
|
XH.webSocketService.shutdown();
|
|
59
59
|
Timer.cancelAll();
|
|
60
|
-
XH.appContainerModel.
|
|
60
|
+
XH.appContainerModel.appLoadObserver.clear();
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
checkAccess(): boolean {
|
|
@@ -51,20 +51,18 @@ export class FeedbackDialogModel extends HoistModel {
|
|
|
51
51
|
* Submit the feedback entry to the activity tracking system.
|
|
52
52
|
*/
|
|
53
53
|
async submitAsync() {
|
|
54
|
-
const {message} = this
|
|
55
|
-
{trackService} = XH;
|
|
56
|
-
|
|
54
|
+
const {message} = this;
|
|
57
55
|
if (!message) this.hide();
|
|
58
56
|
|
|
59
57
|
try {
|
|
60
|
-
trackService.track({
|
|
58
|
+
XH.trackService.track({
|
|
61
59
|
category: 'Feedback',
|
|
62
60
|
message: 'User submitted feedback',
|
|
63
61
|
data: {
|
|
64
62
|
userMessage: this.message
|
|
65
63
|
}
|
|
66
64
|
});
|
|
67
|
-
trackService.pushPendingAsync().linkTo(XH.
|
|
65
|
+
await XH.trackService.pushPendingAsync().linkTo(XH.appLoadObserver);
|
|
68
66
|
XH.successToast('Thank you - your feedback has been sent.');
|
|
69
67
|
this.hide();
|
|
70
68
|
} catch (e) {
|
|
@@ -23,7 +23,7 @@ export declare class AppContainerModel extends HoistModel {
|
|
|
23
23
|
private initCalled;
|
|
24
24
|
appSpec: AppSpec;
|
|
25
25
|
appModel: HoistAppModel;
|
|
26
|
-
|
|
26
|
+
appLoadObserver: TaskObserver;
|
|
27
27
|
appStateModel: AppStateModel;
|
|
28
28
|
pageStateModel: PageStateModel;
|
|
29
29
|
routerModel: RouterModel;
|
|
@@ -87,7 +87,7 @@ export declare class AppContainerModel extends HoistModel {
|
|
|
87
87
|
private startRouter;
|
|
88
88
|
private startOptionsDialog;
|
|
89
89
|
private setAppState;
|
|
90
|
-
private
|
|
90
|
+
private bindInitSequenceToAppLoadObserver;
|
|
91
91
|
private setViewportContent;
|
|
92
92
|
private getViewportContent;
|
|
93
93
|
}
|
package/build/types/core/XH.d.ts
CHANGED
|
@@ -73,8 +73,9 @@ export declare class XHApi {
|
|
|
73
73
|
webSocketService: WebSocketService;
|
|
74
74
|
/**
|
|
75
75
|
* Tracks globally loading promises.
|
|
76
|
-
* Apps should link any async operations that should mask the entire viewport to this
|
|
76
|
+
* Apps should link any async operations that should mask the entire viewport to this observer.
|
|
77
77
|
*/
|
|
78
|
+
get appLoadObserver(): TaskObserver;
|
|
78
79
|
get appLoadModel(): TaskObserver;
|
|
79
80
|
/** Root level application model. */
|
|
80
81
|
get appModel(): HoistAppModel;
|
|
@@ -281,8 +281,8 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
|
|
|
281
281
|
|
|
282
282
|
/** True if any async tasks are pending. */
|
|
283
283
|
get isLoading(): boolean {
|
|
284
|
-
const {
|
|
285
|
-
return
|
|
284
|
+
const {loadObserver, saveTask, selectTask} = this;
|
|
285
|
+
return loadObserver.isPending || saveTask.isPending || selectTask.isPending;
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
/**
|
package/core/XH.ts
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
WebSocketService,
|
|
32
32
|
ClientHealthService
|
|
33
33
|
} from '@xh/hoist/svc';
|
|
34
|
-
import {getLogLevel, setLogLevel, LogLevel} from '@xh/hoist/utils/js';
|
|
34
|
+
import {getLogLevel, setLogLevel, LogLevel, apiDeprecated} from '@xh/hoist/utils/js';
|
|
35
35
|
import {camelCase, flatten, isString, uniqueId} from 'lodash';
|
|
36
36
|
import {Router, State} from 'router5';
|
|
37
37
|
import {CancelFn} from 'router5/types/types/base';
|
|
@@ -164,10 +164,18 @@ export class XHApi {
|
|
|
164
164
|
//----------------------------
|
|
165
165
|
/**
|
|
166
166
|
* Tracks globally loading promises.
|
|
167
|
-
* Apps should link any async operations that should mask the entire viewport to this
|
|
167
|
+
* Apps should link any async operations that should mask the entire viewport to this observer.
|
|
168
168
|
*/
|
|
169
|
+
get appLoadObserver(): TaskObserver {
|
|
170
|
+
return this.acm.appLoadObserver;
|
|
171
|
+
}
|
|
172
|
+
|
|
169
173
|
get appLoadModel(): TaskObserver {
|
|
170
|
-
|
|
174
|
+
apiDeprecated('XH.appLoadModel', {
|
|
175
|
+
v: 'v82',
|
|
176
|
+
msg: 'Use XH.appLoadObserver instead.'
|
|
177
|
+
});
|
|
178
|
+
return this.appLoadObserver;
|
|
171
179
|
}
|
|
172
180
|
|
|
173
181
|
/** Root level application model. */
|
|
@@ -439,7 +447,7 @@ export class XHApi {
|
|
|
439
447
|
*/
|
|
440
448
|
@action
|
|
441
449
|
reloadApp(opts?: ReloadAppOptions | string) {
|
|
442
|
-
never().linkTo(this.
|
|
450
|
+
never().linkTo(this.appLoadObserver);
|
|
443
451
|
|
|
444
452
|
opts = isString(opts) ? {path: opts} : (opts ?? {});
|
|
445
453
|
|
|
@@ -171,7 +171,7 @@ const appContainerView = hoistCmp.factory({
|
|
|
171
171
|
});
|
|
172
172
|
|
|
173
173
|
const appLoadMask = hoistCmp.factory<AppContainerModel>(({model}) =>
|
|
174
|
-
mask({bind: model.
|
|
174
|
+
mask({bind: model.appLoadObserver, spinner: true})
|
|
175
175
|
);
|
|
176
176
|
|
|
177
177
|
const suspendedView = hoistCmp.factory(() => viewport(suspendPanel(), appLoadMask()));
|
|
@@ -25,7 +25,7 @@ export const loginPanel = hoistCmp.factory({
|
|
|
25
25
|
|
|
26
26
|
render({model}) {
|
|
27
27
|
const {loginMessage} = XH.appSpec,
|
|
28
|
-
{
|
|
28
|
+
{loadObserver, warning, isValid, loginInProgress} = model;
|
|
29
29
|
|
|
30
30
|
const onKeyDown = ev => {
|
|
31
31
|
if (ev.key === 'Enter') model.submitAsync();
|
|
@@ -40,7 +40,7 @@ export const loginPanel = hoistCmp.factory({
|
|
|
40
40
|
icon: Icon.login(),
|
|
41
41
|
className: 'xh-login',
|
|
42
42
|
width: 300,
|
|
43
|
-
mask:
|
|
43
|
+
mask: loadObserver,
|
|
44
44
|
items: [
|
|
45
45
|
vspacer(10),
|
|
46
46
|
form(
|
|
@@ -86,7 +86,7 @@ export const [ViewManager, viewManager] = hoistCmp.withFactory<ViewManagerProps>
|
|
|
86
86
|
buttonSide = 'right',
|
|
87
87
|
extraMenuItems = []
|
|
88
88
|
}: ViewManagerProps) {
|
|
89
|
-
const {
|
|
89
|
+
const {loadObserver} = model,
|
|
90
90
|
locModel = useLocalModel(() => new ViewManagerLocalModel(model)),
|
|
91
91
|
save = saveButton({model: locModel, mode: showSaveButton, ...saveButtonProps}),
|
|
92
92
|
revert = revertButton({model: locModel, mode: showRevertButton, ...revertButtonProps}),
|
|
@@ -103,7 +103,7 @@ export const [ViewManager, viewManager] = hoistCmp.withFactory<ViewManagerProps>
|
|
|
103
103
|
}),
|
|
104
104
|
...menuButtonProps
|
|
105
105
|
}),
|
|
106
|
-
content:
|
|
106
|
+
content: loadObserver.isPending
|
|
107
107
|
? box({
|
|
108
108
|
item: spinner({compact: true}),
|
|
109
109
|
alignItems: 'center',
|
|
@@ -143,7 +143,7 @@ const appContainerView = hoistCmp.factory<AppContainerModel>({
|
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
const appLoadMask = hoistCmp.factory<AppContainerModel>(({model}) =>
|
|
146
|
-
mask({bind: model.
|
|
146
|
+
mask({bind: model.appLoadObserver, spinner: true})
|
|
147
147
|
);
|
|
148
148
|
|
|
149
149
|
const bannerList = hoistCmp.factory<AppContainerModel>({
|
|
@@ -26,7 +26,7 @@ export const loginPanel = hoistCmp.factory({
|
|
|
26
26
|
|
|
27
27
|
render({model}) {
|
|
28
28
|
const {loginMessage} = XH.appSpec,
|
|
29
|
-
{isValid,
|
|
29
|
+
{isValid, loadObserver, warning, loginInProgress} = model;
|
|
30
30
|
|
|
31
31
|
return panel({
|
|
32
32
|
className: 'xh-login',
|
|
@@ -34,7 +34,7 @@ export const loginPanel = hoistCmp.factory({
|
|
|
34
34
|
toolbar(filler(), XH.clientAppName, filler()),
|
|
35
35
|
panel({
|
|
36
36
|
className: 'xh-login__body',
|
|
37
|
-
mask:
|
|
37
|
+
mask: loadObserver,
|
|
38
38
|
items: [
|
|
39
39
|
form({
|
|
40
40
|
className: 'xh-login__fields',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "80.0.0-SNAPSHOT.
|
|
3
|
+
"version": "80.0.0-SNAPSHOT.1767974090726",
|
|
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",
|