@xh/hoist 73.0.0-SNAPSHOT.1745446457207 → 73.0.0-SNAPSHOT.1745457790188

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 (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/admin/AppModel.ts +19 -12
  3. package/admin/columns/Core.ts +29 -0
  4. package/admin/columns/Tracking.ts +3 -23
  5. package/admin/tabs/BaseAdminTabModel.ts +17 -0
  6. package/admin/tabs/activity/{ActivityTab.scss → tracking/ActivityTracking.scss} +0 -8
  7. package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +1 -0
  8. package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +5 -1
  9. package/admin/tabs/{activity/ActivityTab.ts → client/ClientTab.ts} +7 -8
  10. package/admin/tabs/{cluster/instances/websocket/WebSocketColumns.ts → client/clients/ClientsColumns.ts} +12 -6
  11. package/admin/tabs/{cluster/instances/websocket/WebSocketModel.ts → client/clients/ClientsModel.ts} +99 -57
  12. package/admin/tabs/{cluster/instances/websocket/WebSocketPanel.ts → client/clients/ClientsPanel.ts} +32 -26
  13. package/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorDetail.ts +9 -5
  14. package/admin/tabs/client/errors/ClientErrors.scss +52 -0
  15. package/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorsPanel.ts +2 -1
  16. package/admin/tabs/cluster/instances/BaseInstanceModel.ts +3 -10
  17. package/admin/tabs/cluster/instances/InstancesTabModel.ts +1 -3
  18. package/admin/tabs/monitor/MonitorTabModel.ts +4 -3
  19. package/admin/tabs/userData/roles/RoleModel.ts +1 -0
  20. package/admin/tabs/userData/roles/RolePanel.ts +4 -2
  21. package/build/types/admin/columns/Core.d.ts +3 -0
  22. package/build/types/admin/tabs/BaseAdminTabModel.d.ts +6 -0
  23. package/build/types/admin/tabs/activity/tracking/ActivityTrackingPanel.d.ts +1 -0
  24. package/build/types/admin/tabs/client/ClientTab.d.ts +1 -0
  25. package/build/types/admin/tabs/{cluster/instances/websocket/WebSocketModel.d.ts → client/clients/ClientsModel.d.ts} +5 -2
  26. package/build/types/admin/tabs/client/clients/ClientsPanel.d.ts +2 -0
  27. package/build/types/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorsPanel.d.ts +1 -0
  28. package/build/types/admin/tabs/cluster/instances/BaseInstanceModel.d.ts +3 -5
  29. package/build/types/admin/tabs/monitor/MonitorTabModel.d.ts +3 -2
  30. package/build/types/svc/EnvironmentService.d.ts +3 -1
  31. package/package.json +1 -1
  32. package/svc/EnvironmentService.ts +6 -4
  33. package/tsconfig.tsbuildinfo +1 -1
  34. package/build/types/admin/tabs/activity/ActivityTab.d.ts +0 -2
  35. package/build/types/admin/tabs/cluster/instances/websocket/WebSocketPanel.d.ts +0 -2
  36. /package/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorsModel.ts +0 -0
  37. /package/admin/tabs/{activity → client}/feedback/FeedbackPanel.ts +0 -0
  38. /package/build/types/admin/tabs/{cluster/instances/websocket/WebSocketColumns.d.ts → client/clients/ClientsColumns.d.ts} +0 -0
  39. /package/build/types/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorDetail.d.ts +0 -0
  40. /package/build/types/admin/tabs/{activity/clienterrors → client/errors}/ClientErrorsModel.d.ts +0 -0
  41. /package/build/types/admin/tabs/{activity → client}/feedback/FeedbackPanel.d.ts +0 -0
@@ -23,16 +23,19 @@ export const clientErrorDetail = hoistCmp.factory<ClientErrorsModel>(({model}) =
23
23
  if (!selectedRecord) return null;
24
24
 
25
25
  return panel({
26
- className: 'xh-admin-activity-detail',
26
+ className: 'xh-admin-client-errors-detail',
27
+ collapsedTitle: 'Error Details',
28
+ collapsedIcon: Icon.info(),
29
+ compactHeader: true,
27
30
  modelConfig: {
28
31
  side: 'bottom',
29
- defaultSize: 370
32
+ defaultSize: 400
30
33
  },
31
34
  item: form({
32
35
  fieldDefaults: {inline: true, readonlyRenderer: valOrNa},
33
36
  item: hframe(
34
37
  div({
35
- className: 'xh-admin-activity-detail__form',
38
+ className: 'xh-admin-client-errors-detail__form',
36
39
  style: {width: '400px'},
37
40
  items: [
38
41
  h3(Icon.info(), 'Error Info'),
@@ -89,12 +92,13 @@ export const clientErrorDetail = hoistCmp.factory<ClientErrorsModel>(({model}) =
89
92
  className: 'xh-border-left',
90
93
  items: [
91
94
  panel({
92
- height: 100,
95
+ flex: 0.5,
93
96
  className: 'xh-border-bottom',
94
97
  items: [
95
98
  h3(Icon.comment(), 'User Message'),
96
99
  div({
97
- className: `xh-admin-activity-detail__message`,
100
+ className: `xh-pad`,
101
+ style: {overflowY: 'auto'},
98
102
  item: userMsg
99
103
  })
100
104
  ],
@@ -0,0 +1,52 @@
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 © 2025 Extremely Heavy Industries Inc.
6
+ */
7
+
8
+ .xh-admin-client-errors-detail {
9
+ &__form {
10
+ overflow-y: auto;
11
+
12
+ .xh-form-field {
13
+ margin: 0;
14
+ padding: 2px var(--xh-pad-px);
15
+
16
+ &.xh-form-field-readonly .xh-form-field-readonly-display {
17
+ padding: var(--xh-pad-half-px);
18
+ }
19
+
20
+ &:nth-child(odd) {
21
+ background-color: var(--xh-grid-bg-odd);
22
+ }
23
+ }
24
+
25
+ .xh-form-field-label {
26
+ font-size: var(--xh-font-size-small-px);
27
+ padding: 0;
28
+ }
29
+ }
30
+
31
+ h3 {
32
+ color: var(--xh-text-color-headings);
33
+ background-color: var(--xh-blue-gray-light);
34
+ margin: 0 !important;
35
+ font-size: var(--xh-font-size-px);
36
+ font-weight: normal;
37
+ padding: var(--xh-pad-half-px) !important;
38
+ border-bottom: var(--xh-border-solid);
39
+
40
+ &:not(:first-child) {
41
+ border-top: var(--xh-border-solid);
42
+ }
43
+
44
+ .xh-dark & {
45
+ background-color: var(--xh-blue-gray-dark);
46
+ }
47
+
48
+ .xh-icon {
49
+ margin-right: var(--xh-pad-px);
50
+ }
51
+ }
52
+ }
@@ -16,13 +16,14 @@ import {Icon} from '@xh/hoist/icon';
16
16
  import {LocalDate} from '@xh/hoist/utils/datetime';
17
17
  import {clientErrorDetail} from './ClientErrorDetail';
18
18
  import {ClientErrorsModel} from './ClientErrorsModel';
19
+ import './ClientErrors.scss';
19
20
 
20
21
  export const clientErrorsPanel = hoistCmp.factory({
21
22
  model: creates(ClientErrorsModel),
22
23
 
23
24
  render() {
24
25
  return panel({
25
- className: 'xh-admin-activity-panel',
26
+ className: 'xh-admin-client-errors-panel',
26
27
  tbar: tbar(),
27
28
  items: [grid(), clientErrorDetail()],
28
29
  mask: 'onLoad'
@@ -5,13 +5,10 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
  import {InstancesTabModel} from '@xh/hoist/admin/tabs/cluster/instances/InstancesTabModel';
8
- import {HoistModel, LoadSpec, lookup, XH} from '@xh/hoist/core';
9
- import {createRef} from 'react';
10
- import {isDisplayed} from '@xh/hoist/utils/js';
11
-
12
- export class BaseInstanceModel extends HoistModel {
13
- viewRef = createRef<HTMLElement>();
8
+ import {LoadSpec, lookup, XH} from '@xh/hoist/core';
9
+ import {BaseAdminTabModel} from '@xh/hoist/admin/tabs/BaseAdminTabModel';
14
10
 
11
+ export class BaseInstanceModel extends BaseAdminTabModel {
15
12
  @lookup(() => InstancesTabModel) parent: InstancesTabModel;
16
13
 
17
14
  get instanceName(): string {
@@ -30,10 +27,6 @@ export class BaseInstanceModel extends HoistModel {
30
27
  });
31
28
  }
32
29
 
33
- get isVisible() {
34
- return isDisplayed(this.viewRef.current);
35
- }
36
-
37
30
  //-------------------
38
31
  // Implementation
39
32
  //-------------------
@@ -15,7 +15,6 @@ import {
15
15
  } from '@xh/hoist/admin/tabs/cluster/instances/memory/MemoryMonitorModel';
16
16
  import {memoryMonitorPanel} from '@xh/hoist/admin/tabs/cluster/instances/memory/MemoryMonitorPanel';
17
17
  import {servicePanel} from '@xh/hoist/admin/tabs/cluster/instances/services/ServicePanel';
18
- import {webSocketPanel} from '@xh/hoist/admin/tabs/cluster/instances/websocket/WebSocketPanel';
19
18
  import {badge} from '@xh/hoist/cmp/badge';
20
19
  import {GridContextMenuSpec, GridModel, numberCol} from '@xh/hoist/cmp/grid';
21
20
  import {hbox} from '@xh/hoist/cmp/layout';
@@ -205,8 +204,7 @@ export class InstancesTabModel extends HoistModel {
205
204
  content: connPoolMonitorPanel
206
205
  },
207
206
  {id: 'environment', icon: Icon.globe(), content: serverEnvPanel},
208
- {id: 'services', icon: Icon.gears(), content: servicePanel},
209
- {id: 'webSockets', title: 'WebSockets', icon: Icon.bolt(), content: webSocketPanel}
207
+ {id: 'services', icon: Icon.gears(), content: servicePanel}
210
208
  ]
211
209
  });
212
210
  }
@@ -5,15 +5,16 @@
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
7
  import {MonitorResults, MonitorStatus} from '@xh/hoist/admin/tabs/monitor/Types';
8
- import {HoistModel, LoadSpec, managed, persist, XH} from '@xh/hoist/core';
8
+ import {LoadSpec, managed, persist, XH} from '@xh/hoist/core';
9
9
  import {Icon} from '@xh/hoist/icon';
10
10
  import {action, bindable, computed, makeObservable, observable} from '@xh/hoist/mobx';
11
11
  import {Timer} from '@xh/hoist/utils/async';
12
12
  import {SECONDS} from '@xh/hoist/utils/datetime';
13
13
  import {pluralize} from '@xh/hoist/utils/js';
14
14
  import {filter, isEqual, minBy, sortBy} from 'lodash';
15
+ import {BaseAdminTabModel} from '@xh/hoist/admin/tabs/BaseAdminTabModel';
15
16
 
16
- export class MonitorTabModel extends HoistModel {
17
+ export class MonitorTabModel extends BaseAdminTabModel {
17
18
  override persistWith = {localStorageKey: 'xhAdminClientMonitorState'};
18
19
 
19
20
  @observable.ref results: MonitorResults[] = [];
@@ -73,7 +74,7 @@ export class MonitorTabModel extends HoistModel {
73
74
  }
74
75
 
75
76
  override async doLoadAsync(loadSpec: LoadSpec) {
76
- if (!XH.pageIsVisible) return;
77
+ if (!this.isVisible) return;
77
78
 
78
79
  try {
79
80
  const results = await XH.fetchJson({url: 'monitorResultsAdmin/results', loadSpec});
@@ -328,6 +328,7 @@ export class RoleModel extends HoistModel {
328
328
  {
329
329
  ...actionCol,
330
330
  actionsShowOnHoverOnly: true,
331
+ excludeFromChooser: true,
331
332
  width: calcActionColWidth(1),
332
333
  actions: [this.editAction()],
333
334
  omit: this.readonly
@@ -8,7 +8,7 @@ import {recategorizeDialog} from '@xh/hoist/admin/tabs/userData/roles/recategori
8
8
  import {grid} from '@xh/hoist/cmp/grid';
9
9
  import {fragment, hframe, vframe} from '@xh/hoist/cmp/layout';
10
10
  import {creates, hoistCmp} from '@xh/hoist/core';
11
- import {button} from '@xh/hoist/desktop/cmp/button';
11
+ import {button, colChooserButton} from '@xh/hoist/desktop/cmp/button';
12
12
  import {errorMessage} from '@xh/hoist/cmp/error';
13
13
  import {filterChooser} from '@xh/hoist/desktop/cmp/filter';
14
14
  import {switchInput} from '@xh/hoist/desktop/cmp/input';
@@ -50,7 +50,9 @@ export const rolePanel = hoistCmp.factory({
50
50
  bind: 'showInGroups',
51
51
  label: 'Group by Category',
52
52
  labelSide: 'left'
53
- })
53
+ }),
54
+ '-',
55
+ colChooserButton()
54
56
  ],
55
57
  item: hframe(vframe(grid(), roleGraph()), detailsPanel())
56
58
  }),
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { ColumnSpec } from '@xh/hoist/cmp/grid';
2
3
  export declare const name: ColumnSpec;
3
4
  export declare const type: ColumnSpec;
@@ -5,3 +6,5 @@ export declare const description: ColumnSpec;
5
6
  export declare const notes: ColumnSpec;
6
7
  export declare const note: ColumnSpec;
7
8
  export declare const timestampNoYear: ColumnSpec;
9
+ export declare function badgeRenderer(v: any): "-" | import("react").ReactElement<import("@xh/hoist/cmp/badge").BadgeProps, any>;
10
+ export declare const badgeCol: ColumnSpec;
@@ -0,0 +1,6 @@
1
+ /// <reference types="react" />
2
+ import { HoistModel } from '@xh/hoist/core';
3
+ export declare class BaseAdminTabModel extends HoistModel {
4
+ viewRef: import("react").RefObject<HTMLElement>;
5
+ get isVisible(): boolean;
6
+ }
@@ -1,2 +1,3 @@
1
1
  import { ActivityTrackingModel } from './ActivityTrackingModel';
2
+ import './ActivityTracking.scss';
2
3
  export declare const activityTrackingPanel: import("@xh/hoist/core").ElementFactory<import("@xh/hoist/core").DefaultHoistProps<ActivityTrackingModel>>;
@@ -0,0 +1 @@
1
+ export declare const clientTab: import("@xh/hoist/core").ElementFactory<import("@xh/hoist/core").DefaultHoistProps<import("@xh/hoist/core").HoistModel>>;
@@ -1,10 +1,11 @@
1
- import { BaseInstanceModel } from '@xh/hoist/admin/tabs/cluster/instances/BaseInstanceModel';
2
1
  import { GridModel } from '@xh/hoist/cmp/grid';
3
2
  import { LoadSpec } from '@xh/hoist/core';
4
3
  import { RecordActionSpec, StoreRecord } from '@xh/hoist/data';
5
- export declare class WebSocketModel extends BaseInstanceModel {
4
+ import { BaseAdminTabModel } from '@xh/hoist/admin/tabs/BaseAdminTabModel';
5
+ export declare class ClientsModel extends BaseAdminTabModel {
6
6
  lastRefresh: number;
7
7
  gridModel: GridModel;
8
+ groupBy: 'user' | 'instance';
8
9
  private _timer;
9
10
  forceSuspendAction: RecordActionSpec;
10
11
  reqHealthReportAction: RecordActionSpec;
@@ -12,5 +13,7 @@ export declare class WebSocketModel extends BaseInstanceModel {
12
13
  doLoadAsync(loadSpec: LoadSpec): Promise<void>;
13
14
  forceSuspendAsync(toRecs: StoreRecord[]): Promise<void>;
14
15
  requestHealthReportAsync(toRecs: StoreRecord[]): Promise<void>;
16
+ private createGridModel;
15
17
  private bulkPush;
18
+ private applyGroupBy;
16
19
  }
@@ -0,0 +1,2 @@
1
+ import { ClientsModel } from './ClientsModel';
2
+ export declare const clientsPanel: import("@xh/hoist/core").ElementFactory<import("@xh/hoist/core").DefaultHoistProps<ClientsModel>>;
@@ -1,2 +1,3 @@
1
1
  import { ClientErrorsModel } from './ClientErrorsModel';
2
+ import './ClientErrors.scss';
2
3
  export declare const clientErrorsPanel: import("@xh/hoist/core").ElementFactory<import("@xh/hoist/core").DefaultHoistProps<ClientErrorsModel>>;
@@ -1,11 +1,9 @@
1
- /// <reference types="react" />
2
1
  import { InstancesTabModel } from '@xh/hoist/admin/tabs/cluster/instances/InstancesTabModel';
3
- import { HoistModel, LoadSpec } from '@xh/hoist/core';
4
- export declare class BaseInstanceModel extends HoistModel {
5
- viewRef: import("react").RefObject<HTMLElement>;
2
+ import { LoadSpec } from '@xh/hoist/core';
3
+ import { BaseAdminTabModel } from '@xh/hoist/admin/tabs/BaseAdminTabModel';
4
+ export declare class BaseInstanceModel extends BaseAdminTabModel {
6
5
  parent: InstancesTabModel;
7
6
  get instanceName(): string;
8
7
  handleLoadException(e: unknown, loadSpec: LoadSpec): void;
9
- get isVisible(): boolean;
10
8
  private isInstanceNotFound;
11
9
  }
@@ -1,7 +1,8 @@
1
1
  import { MonitorResults, MonitorStatus } from '@xh/hoist/admin/tabs/monitor/Types';
2
- import { HoistModel, LoadSpec } from '@xh/hoist/core';
2
+ import { LoadSpec } from '@xh/hoist/core';
3
3
  import { Timer } from '@xh/hoist/utils/async';
4
- export declare class MonitorTabModel extends HoistModel {
4
+ import { BaseAdminTabModel } from '@xh/hoist/admin/tabs/BaseAdminTabModel';
5
+ export declare class MonitorTabModel extends BaseAdminTabModel {
5
6
  persistWith: {
6
7
  localStorageKey: string;
7
8
  };
@@ -31,7 +31,9 @@ export declare class EnvironmentService extends HoistService {
31
31
  isMinHoistCoreVersion(version: string): boolean;
32
32
  isMaxHoistCoreVersion(version: string): boolean;
33
33
  /**
34
- * Update critical environment information from server.
34
+ * Update critical environment information from server, including current app version + build,
35
+ * upgrade prompt mode, and alert banner.
36
+ *
35
37
  * @internal - not for app use. Called by `pollTimer` and as needed by Hoist code.
36
38
  */
37
39
  pollServerAsync(): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "73.0.0-SNAPSHOT.1745446457207",
3
+ "version": "73.0.0-SNAPSHOT.1745457790188",
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",
@@ -113,7 +113,9 @@ export class EnvironmentService extends HoistService {
113
113
  }
114
114
 
115
115
  /**
116
- * Update critical environment information from server.
116
+ * Update critical environment information from server, including current app version + build,
117
+ * upgrade prompt mode, and alert banner.
118
+ *
117
119
  * @internal - not for app use. Called by `pollTimer` and as needed by Hoist code.
118
120
  */
119
121
  async pollServerAsync() {
@@ -125,15 +127,15 @@ export class EnvironmentService extends HoistService {
125
127
  return;
126
128
  }
127
129
 
128
- // Update config/interval, and server info
130
+ // Update config/interval, server info, and alert banner.
129
131
  const {pollConfig, instanceName, alertBanner, appVersion, appBuild} = data;
130
132
  this.pollConfig = pollConfig;
131
133
  this.pollTimer.setInterval(this.pollIntervalMs);
132
134
  this.setServerInfo(instanceName, appVersion, appBuild);
133
135
  XH.alertBannerService.updateBanner(alertBanner);
134
136
 
135
- // Handle version change
136
- if (appVersion != XH.getEnv('appVersion') || appBuild != XH.getEnv('appBuild')) {
137
+ // Handle version change - compare to constants baked into client build.
138
+ if (appVersion != XH.appVersion || appBuild != XH.appBuild) {
137
139
  // force the user to refresh or prompt the user to refresh via the banner according to config
138
140
  // build checked to trigger refresh across SNAPSHOT updates in lower environments
139
141
  const {onVersionChange} = pollConfig;