@xh/hoist 73.0.0-SNAPSHOT.1746025071597 → 73.0.0-SNAPSHOT.1746050068813

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 (48) hide show
  1. package/CHANGELOG.md +8 -3
  2. package/admin/AdminUtils.ts +5 -0
  3. package/admin/AppModel.ts +19 -7
  4. package/admin/columns/Rest.ts +8 -0
  5. package/admin/columns/Tracking.ts +72 -0
  6. package/admin/tabs/activity/tracking/ActivityTracking.scss +18 -0
  7. package/admin/tabs/activity/tracking/ActivityTrackingModel.ts +309 -216
  8. package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +81 -51
  9. package/admin/tabs/activity/tracking/chart/AggChartModel.ts +218 -0
  10. package/admin/tabs/activity/tracking/chart/AggChartPanel.ts +61 -0
  11. package/admin/tabs/activity/tracking/datafields/DataFieldsEditor.ts +147 -0
  12. package/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.ts +133 -0
  13. package/admin/tabs/activity/tracking/detail/ActivityDetailModel.ts +123 -60
  14. package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +106 -58
  15. package/admin/tabs/client/ClientTab.ts +2 -4
  16. package/admin/tabs/cluster/instances/memory/MemoryMonitorModel.ts +1 -2
  17. package/admin/tabs/general/GeneralTab.ts +2 -0
  18. package/build/types/admin/AdminUtils.d.ts +2 -0
  19. package/build/types/admin/AppModel.d.ts +4 -1
  20. package/build/types/admin/columns/Rest.d.ts +1 -0
  21. package/build/types/admin/columns/Tracking.d.ts +6 -0
  22. package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +31 -28
  23. package/build/types/admin/tabs/activity/tracking/chart/AggChartModel.d.ts +33 -0
  24. package/build/types/admin/tabs/activity/tracking/chart/AggChartPanel.d.ts +2 -0
  25. package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditor.d.ts +2 -0
  26. package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.d.ts +46 -0
  27. package/build/types/admin/tabs/activity/tracking/detail/ActivityDetailModel.d.ts +14 -1
  28. package/build/types/cmp/form/FormModel.d.ts +19 -30
  29. package/build/types/cmp/form/field/SubformsFieldModel.d.ts +25 -22
  30. package/build/types/core/HoistBase.d.ts +2 -2
  31. package/build/types/data/cube/CubeField.d.ts +4 -5
  32. package/build/types/desktop/cmp/appOption/AutoRefreshAppOption.d.ts +3 -3
  33. package/build/types/desktop/cmp/appOption/ThemeAppOption.d.ts +3 -3
  34. package/cmp/error/ErrorBoundaryModel.ts +1 -1
  35. package/cmp/form/FormModel.ts +20 -28
  36. package/cmp/form/field/SubformsFieldModel.ts +28 -22
  37. package/cmp/grid/columns/DatesTimes.ts +1 -2
  38. package/cmp/grid/impl/GridHScrollbar.ts +1 -2
  39. package/core/HoistBase.ts +12 -12
  40. package/data/cube/CubeField.ts +17 -18
  41. package/package.json +1 -1
  42. package/tsconfig.tsbuildinfo +1 -1
  43. package/admin/tabs/activity/tracking/charts/ChartsModel.ts +0 -218
  44. package/admin/tabs/activity/tracking/charts/ChartsPanel.ts +0 -76
  45. package/build/types/admin/tabs/activity/tracking/charts/ChartsModel.d.ts +0 -34
  46. package/build/types/admin/tabs/activity/tracking/charts/ChartsPanel.d.ts +0 -2
  47. /package/admin/tabs/{client → general}/feedback/FeedbackPanel.ts +0 -0
  48. /package/build/types/admin/tabs/{client → general}/feedback/FeedbackPanel.d.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -11,11 +11,16 @@ and new properties on `TrackLog`.
11
11
 
12
12
  * Added a new "Clients" Admin Console tab- a consolidated view of all websocket-connected clients
13
13
  across all instances in the cluster.
14
+ * Major Enhancements to Admin 'User Activity' tab:
15
+ * Provide user customizable persisted views via ViewManager.
16
+ * Provide the ability to promote data in `data` block to grids for aggregation, reporting and charting.
17
+ * Improved charting.
18
+ * Enhanced all messages with new `tabId` and `loadId` properties, to disambiguate activity for
19
+ users with multiple browser tabs and multiple full refreshes/restarts of a client app within
20
+ the same tab.
14
21
  * Updated `FormModel` to support `persistWith` for storing and recalling its values, including
15
22
  developer options to persist all or a provided subset of fields.
16
- * Enhanced all activity tracking messages with new `tabId` and `loadId` properties, to disambiguate
17
- tracking activity for users with multiple browser tabs and multiple full refreshes/restarts of a
18
- client app within the same tab.
23
+
19
24
 
20
25
  ### 🐞 Bug Fixes
21
26
 
@@ -4,6 +4,7 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
+ import {AppModel} from '@xh/hoist/admin/AppModel';
7
8
  import {XH} from '@xh/hoist/core';
8
9
  import {LocalDate} from '@xh/hoist/utils/datetime';
9
10
 
@@ -21,3 +22,7 @@ export function exportFilename(moduleName: string): string {
21
22
  export function exportFilenameWithDate(moduleName: string): () => string {
22
23
  return () => `${XH.appCode}-${moduleName}-${LocalDate.today()}`;
23
24
  }
25
+
26
+ export function getAppModel<T extends AppModel>() {
27
+ return XH.appModel as T;
28
+ }
package/admin/AppModel.ts CHANGED
@@ -7,22 +7,22 @@
7
7
  import {clusterTab} from '@xh/hoist/admin/tabs/cluster/ClusterTab';
8
8
  import {GridModel} from '@xh/hoist/cmp/grid';
9
9
  import {TabConfig, TabContainerModel} from '@xh/hoist/cmp/tab';
10
- import {HoistAppModel, managed, XH} from '@xh/hoist/core';
10
+ import {ViewManagerModel} from '@xh/hoist/cmp/viewmanager';
11
+ import {HoistAppModel, XH} from '@xh/hoist/core';
11
12
  import {Icon} from '@xh/hoist/icon';
12
13
  import {without} from 'lodash';
13
14
  import {Route} from 'router5';
14
15
  import {activityTrackingPanel} from './tabs/activity/tracking/ActivityTrackingPanel';
16
+ import {clientTab} from './tabs/client/ClientTab';
15
17
  import {generalTab} from './tabs/general/GeneralTab';
16
18
  import {monitorTab} from './tabs/monitor/MonitorTab';
17
19
  import {userDataTab} from './tabs/userData/UserDataTab';
18
- import {clientTab} from './tabs/client/ClientTab';
19
20
 
20
21
  export class AppModel extends HoistAppModel {
21
- static instance: AppModel;
22
-
23
- @managed
24
22
  tabModel: TabContainerModel;
25
23
 
24
+ viewManagerModels: Record<string, ViewManagerModel> = {};
25
+
26
26
  static get readonly() {
27
27
  return !XH.getUser().isHoistAdmin;
28
28
  }
@@ -40,6 +40,11 @@ export class AppModel extends HoistAppModel {
40
40
  GridModel.DEFAULT_AUTOSIZE_MODE = 'managed';
41
41
  }
42
42
 
43
+ override async initAsync() {
44
+ await this.initViewManagerModelsAsync();
45
+ await super.initAsync();
46
+ }
47
+
43
48
  override getRoutes(): Route[] {
44
49
  return [
45
50
  {
@@ -65,6 +70,7 @@ export class AppModel extends HoistAppModel {
65
70
  children: [
66
71
  {name: 'about', path: '/about'},
67
72
  {name: 'config', path: '/config'},
73
+ {name: 'feedback', path: '/feedback'},
68
74
  {name: 'alertBanner', path: '/alertBanner'}
69
75
  ]
70
76
  },
@@ -91,8 +97,7 @@ export class AppModel extends HoistAppModel {
91
97
  path: '/clients',
92
98
  children: [
93
99
  {name: 'connections', path: '/connections'},
94
- {name: 'errors', path: '/errors'},
95
- {name: 'feedback', path: '/feedback'}
100
+ {name: 'errors', path: '/errors'}
96
101
  ]
97
102
  },
98
103
  {
@@ -161,4 +166,11 @@ export class AppModel extends HoistAppModel {
161
166
  const appCodes = without(XH.clientApps, XH.clientAppCode, 'mobile');
162
167
  return appCodes.find(it => it === 'app') ?? appCodes[0];
163
168
  }
169
+
170
+ async initViewManagerModelsAsync() {
171
+ this.viewManagerModels.activityTracking = await ViewManagerModel.createAsync({
172
+ type: 'xhAdminActivityTrackingView',
173
+ typeDisplayName: 'View'
174
+ });
175
+ }
164
176
  }
@@ -6,12 +6,20 @@
6
6
  */
7
7
  import {ColumnSpec} from '@xh/hoist/cmp/grid/columns';
8
8
  import * as Col from '@xh/hoist/cmp/grid/columns';
9
+ import {dateTimeRenderer} from '@xh/hoist/format';
9
10
 
10
11
  export const dateCreated: ColumnSpec = {
11
12
  field: {name: 'dateCreated', type: 'date'},
12
13
  ...Col.dateTime
13
14
  };
14
15
 
16
+ export const dateCreatedNoYear: ColumnSpec = {
17
+ ...Col.dateTimeSec,
18
+ field: {name: 'dateCreated', type: 'date'},
19
+ tooltip: true,
20
+ renderer: dateTimeRenderer({fmt: 'MMM DD HH:mm:ss'})
21
+ };
22
+
15
23
  export const dateCreatedWithSec: ColumnSpec = {
16
24
  field: {name: 'dateCreated', type: 'date'},
17
25
  ...Col.dateTimeSec
@@ -8,8 +8,10 @@ import {badgeCol, badgeRenderer} from '@xh/hoist/admin/columns';
8
8
  import {RangeAggregator} from '@xh/hoist/admin/tabs/activity/aggregators/RangeAggregator';
9
9
  import * as Col from '@xh/hoist/cmp/grid/columns';
10
10
  import {ColumnSpec} from '@xh/hoist/cmp/grid/columns';
11
+ import {TrackSeverity} from '@xh/hoist/core';
11
12
  import {fmtDate, fmtSpan, numberRenderer} from '@xh/hoist/format';
12
13
  import {Icon} from '@xh/hoist/icon';
14
+ import {ReactElement} from 'react';
13
15
 
14
16
  export const appBuild: ColumnSpec = {
15
17
  field: {
@@ -109,6 +111,32 @@ export const device: ColumnSpec = {
109
111
  width: 100
110
112
  };
111
113
 
114
+ export const deviceIcon: ColumnSpec = {
115
+ field: device.field,
116
+ headerName: Icon.desktop(),
117
+ headerTooltip: 'Device',
118
+ tooltip: true,
119
+ resizable: false,
120
+ align: 'center',
121
+ width: 50,
122
+ renderer: v => {
123
+ // See Hoist Core `Device.groovy` for enumeration
124
+ switch (v) {
125
+ case 'ANDROID':
126
+ case 'IPAD':
127
+ case 'IPHONE':
128
+ case 'IPOD':
129
+ return Icon.phone();
130
+ case 'LINUX':
131
+ case 'MAC':
132
+ case 'WINDOWS':
133
+ return Icon.desktop();
134
+ default:
135
+ return Icon.questionCircle();
136
+ }
137
+ }
138
+ };
139
+
112
140
  export const elapsed: ColumnSpec = {
113
141
  field: {
114
142
  name: 'elapsed',
@@ -196,6 +224,34 @@ export const severity: ColumnSpec = {
196
224
  width: 80
197
225
  };
198
226
 
227
+ export const severityIcon: ColumnSpec = {
228
+ field: severity.field,
229
+ headerName: Icon.info(),
230
+ headerTooltip: 'Severity',
231
+ tooltip: true,
232
+ resizable: false,
233
+ align: 'center',
234
+ width: 50,
235
+ renderer: v => getSeverityIcon(v)
236
+ };
237
+
238
+ export function getSeverityIcon(severity: TrackSeverity): ReactElement {
239
+ if (!severity) return null;
240
+
241
+ switch (severity) {
242
+ case 'DEBUG':
243
+ return Icon.code();
244
+ case 'INFO':
245
+ return Icon.infoCircle({className: 'xh-text-color-muted'});
246
+ case 'WARN':
247
+ return Icon.warning({intent: 'warning'});
248
+ case 'ERROR':
249
+ return Icon.error({intent: 'danger'});
250
+ default:
251
+ return Icon.questionCircle();
252
+ }
253
+ }
254
+
199
255
  export const tabId: ColumnSpec = {
200
256
  field: {
201
257
  name: 'tabId',
@@ -214,6 +270,22 @@ export const url: ColumnSpec = {
214
270
  autosizeMaxWidth: 400
215
271
  };
216
272
 
273
+ export const urlPathOnly: ColumnSpec = {
274
+ field: url.field,
275
+ width: 250,
276
+ autosizeMaxWidth: 400,
277
+ tooltip: true,
278
+ renderer: v => {
279
+ if (!v) return null;
280
+ try {
281
+ const urlObj = new URL(v);
282
+ return urlObj.pathname;
283
+ } catch (ignored) {
284
+ return v;
285
+ }
286
+ }
287
+ };
288
+
217
289
  export const userAgent: ColumnSpec = {
218
290
  field: {
219
291
  name: 'userAgent',
@@ -31,6 +31,24 @@
31
31
  margin-right: var(--xh-pad-half-px);
32
32
  }
33
33
  }
34
+
35
+ &__data-fields-editor {
36
+ width: 50vw;
37
+ min-width: 700px;
38
+ max-width: 1000px;
39
+ min-height: 200px;
40
+
41
+ &__row {
42
+ align-items: flex-start;
43
+ flex: none;
44
+ margin-left: 5px;
45
+ margin-right: 5px;
46
+
47
+ &:first-child {
48
+ margin-top: 5px;
49
+ }
50
+ }
51
+ }
34
52
  }
35
53
 
36
54
  .xh-admin-activity-detail {