@xh/hoist 73.0.0-SNAPSHOT.1746025071597 → 73.0.0-SNAPSHOT.1746050507413
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 +9 -3
- package/admin/AdminUtils.ts +5 -0
- package/admin/AppModel.ts +19 -7
- package/admin/columns/Rest.ts +8 -0
- package/admin/columns/Tracking.ts +72 -0
- package/admin/tabs/activity/tracking/ActivityTracking.scss +19 -0
- package/admin/tabs/activity/tracking/ActivityTrackingModel.ts +309 -216
- package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +81 -51
- package/admin/tabs/activity/tracking/chart/AggChartModel.ts +218 -0
- package/admin/tabs/activity/tracking/chart/AggChartPanel.ts +61 -0
- package/admin/tabs/activity/tracking/datafields/DataFieldsEditor.ts +148 -0
- package/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.ts +133 -0
- package/admin/tabs/activity/tracking/detail/ActivityDetailModel.ts +123 -60
- package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +106 -58
- package/admin/tabs/client/ClientTab.ts +2 -4
- package/admin/tabs/cluster/instances/memory/MemoryMonitorModel.ts +1 -2
- package/admin/tabs/general/GeneralTab.ts +2 -0
- package/build/types/admin/AdminUtils.d.ts +2 -0
- package/build/types/admin/AppModel.d.ts +4 -1
- package/build/types/admin/columns/Rest.d.ts +1 -0
- package/build/types/admin/columns/Tracking.d.ts +6 -0
- package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +31 -28
- package/build/types/admin/tabs/activity/tracking/chart/AggChartModel.d.ts +33 -0
- package/build/types/admin/tabs/activity/tracking/chart/AggChartPanel.d.ts +2 -0
- package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditor.d.ts +2 -0
- package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.d.ts +46 -0
- package/build/types/admin/tabs/activity/tracking/detail/ActivityDetailModel.d.ts +14 -1
- package/build/types/cmp/form/FormModel.d.ts +19 -30
- package/build/types/cmp/form/field/SubformsFieldModel.d.ts +25 -22
- package/build/types/core/HoistBase.d.ts +2 -2
- package/build/types/data/cube/CubeField.d.ts +4 -5
- package/build/types/desktop/cmp/appOption/AutoRefreshAppOption.d.ts +3 -3
- package/build/types/desktop/cmp/appOption/ThemeAppOption.d.ts +3 -3
- package/cmp/error/ErrorBoundaryModel.ts +1 -1
- package/cmp/form/FormModel.ts +20 -28
- package/cmp/form/field/SubformsFieldModel.ts +28 -22
- package/cmp/grid/columns/DatesTimes.ts +1 -2
- package/cmp/grid/impl/GridHScrollbar.ts +1 -2
- package/core/HoistBase.ts +12 -12
- package/data/cube/CubeField.ts +17 -18
- package/desktop/cmp/button/DashCanvasAddViewButton.ts +1 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/admin/tabs/activity/tracking/charts/ChartsModel.ts +0 -218
- package/admin/tabs/activity/tracking/charts/ChartsPanel.ts +0 -76
- package/build/types/admin/tabs/activity/tracking/charts/ChartsModel.d.ts +0 -34
- package/build/types/admin/tabs/activity/tracking/charts/ChartsPanel.d.ts +0 -2
- /package/admin/tabs/{client → general}/feedback/FeedbackPanel.ts +0 -0
- /package/build/types/admin/tabs/{client → general}/feedback/FeedbackPanel.d.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -11,16 +11,22 @@ 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
|
-
|
|
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
|
|
|
22
27
|
* Fixed drag-and-drop usability issues with the mobile `ColChooser`.
|
|
23
28
|
* Made `GridModel.defaultGroupSortFn` null-safe and improved type signature.
|
|
29
|
+
* Disable `dashCanvasAddViewButton` if there are no `menuItems` to show.
|
|
24
30
|
|
|
25
31
|
### ⚙️ Typescript API Adjustments
|
|
26
32
|
|
package/admin/AdminUtils.ts
CHANGED
|
@@ -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 {
|
|
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
|
}
|
package/admin/columns/Rest.ts
CHANGED
|
@@ -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,25 @@
|
|
|
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
|
+
gap: 5px;
|
|
47
|
+
|
|
48
|
+
&:first-child {
|
|
49
|
+
margin-top: 5px;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
.xh-admin-activity-detail {
|