@xh/hoist 73.0.0-SNAPSHOT.1745976013413 → 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 (57) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/admin/AdminUtils.ts +5 -0
  3. package/admin/App.scss +6 -0
  4. package/admin/AppModel.ts +19 -7
  5. package/admin/{tabs/client/clients/ClientsColumns.ts → columns/Clients.ts} +20 -53
  6. package/admin/columns/Core.ts +34 -35
  7. package/admin/columns/Rest.ts +8 -0
  8. package/admin/columns/Tracking.ts +144 -42
  9. package/admin/columns/index.ts +1 -0
  10. package/admin/tabs/activity/tracking/ActivityTracking.scss +18 -0
  11. package/admin/tabs/activity/tracking/ActivityTrackingModel.ts +309 -210
  12. package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +81 -51
  13. package/admin/tabs/activity/tracking/chart/AggChartModel.ts +218 -0
  14. package/admin/tabs/activity/tracking/chart/AggChartPanel.ts +61 -0
  15. package/admin/tabs/activity/tracking/datafields/DataFieldsEditor.ts +147 -0
  16. package/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.ts +133 -0
  17. package/admin/tabs/activity/tracking/detail/ActivityDetailModel.ts +123 -59
  18. package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +110 -54
  19. package/admin/tabs/client/ClientTab.ts +2 -4
  20. package/admin/tabs/client/clients/ClientsModel.ts +10 -11
  21. package/admin/tabs/cluster/instances/memory/MemoryMonitorModel.ts +1 -2
  22. package/admin/tabs/general/GeneralTab.ts +2 -0
  23. package/build/types/admin/AdminUtils.d.ts +2 -0
  24. package/build/types/admin/AppModel.d.ts +4 -1
  25. package/build/types/admin/{tabs/client/clients/ClientsColumns.d.ts → columns/Clients.d.ts} +3 -7
  26. package/build/types/admin/columns/Core.d.ts +5 -5
  27. package/build/types/admin/columns/Rest.d.ts +1 -0
  28. package/build/types/admin/columns/Tracking.d.ts +13 -4
  29. package/build/types/admin/columns/index.d.ts +1 -0
  30. package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +31 -28
  31. package/build/types/admin/tabs/activity/tracking/chart/AggChartModel.d.ts +33 -0
  32. package/build/types/admin/tabs/activity/tracking/chart/AggChartPanel.d.ts +2 -0
  33. package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditor.d.ts +2 -0
  34. package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.d.ts +46 -0
  35. package/build/types/admin/tabs/activity/tracking/detail/ActivityDetailModel.d.ts +14 -1
  36. package/build/types/cmp/form/FormModel.d.ts +19 -30
  37. package/build/types/cmp/form/field/SubformsFieldModel.d.ts +25 -22
  38. package/build/types/core/HoistBase.d.ts +2 -2
  39. package/build/types/data/cube/CubeField.d.ts +4 -5
  40. package/build/types/desktop/cmp/appOption/AutoRefreshAppOption.d.ts +3 -3
  41. package/build/types/desktop/cmp/appOption/ThemeAppOption.d.ts +3 -3
  42. package/cmp/error/ErrorBoundaryModel.ts +1 -1
  43. package/cmp/form/FormModel.ts +20 -28
  44. package/cmp/form/field/SubformsFieldModel.ts +28 -22
  45. package/cmp/grid/columns/DatesTimes.ts +1 -2
  46. package/cmp/grid/impl/GridHScrollbar.ts +1 -2
  47. package/core/HoistBase.ts +12 -12
  48. package/data/cube/CubeField.ts +17 -18
  49. package/package.json +1 -1
  50. package/svc/TrackService.ts +2 -0
  51. package/tsconfig.tsbuildinfo +1 -1
  52. package/admin/tabs/activity/tracking/charts/ChartsModel.ts +0 -218
  53. package/admin/tabs/activity/tracking/charts/ChartsPanel.ts +0 -76
  54. package/build/types/admin/tabs/activity/tracking/charts/ChartsModel.d.ts +0 -34
  55. package/build/types/admin/tabs/activity/tracking/charts/ChartsPanel.d.ts +0 -2
  56. /package/admin/tabs/{client → general}/feedback/FeedbackPanel.ts +0 -0
  57. /package/build/types/admin/tabs/{client → general}/feedback/FeedbackPanel.d.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -4,15 +4,24 @@
4
4
 
5
5
  ### 💥 Breaking Changes (upgrade difficulty: 🟢 TRIVIAL - minor upgrade to Hoist Core)
6
6
 
7
- Requires `hoist-core >= 30.0` with new APIs to support the consolidated Admin Console "Clients" tab.
7
+ Requires `hoist-core >= 30.0` with new APIs to support the consolidated Admin Console "Clients" tab
8
+ and new properties on `TrackLog`.
8
9
 
9
10
  ### 🎁 New Features
10
11
 
11
12
  * Added a new "Clients" Admin Console tab- a consolidated view of all websocket-connected clients
12
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.
13
21
  * Updated `FormModel` to support `persistWith` for storing and recalling its values, including
14
22
  developer options to persist all or a provided subset of fields.
15
23
 
24
+
16
25
  ### 🐞 Bug Fixes
17
26
 
18
27
  * Fixed drag-and-drop usability issues with the mobile `ColChooser`.
@@ -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/App.scss CHANGED
@@ -25,6 +25,12 @@
25
25
  height: 80vh;
26
26
  width: 80vw;
27
27
  }
28
+
29
+ .xh-badge-col {
30
+ --xh-badge-font-size: 0.9em;
31
+ background-color: var(--xh-intent-primary-darker);
32
+ font-family: var(--xh-font-family-mono);
33
+ }
28
34
  }
29
35
 
30
36
  .xh-units-label {
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
  }
@@ -4,11 +4,19 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {badgeCol} from '@xh/hoist/admin/columns';
8
7
  import * as Col from '@xh/hoist/cmp/grid/columns';
9
8
  import {ColumnSpec} from '@xh/hoist/cmp/grid/columns';
10
9
  import {Icon} from '@xh/hoist/icon';
11
10
 
11
+ export const createdTime: ColumnSpec = {
12
+ field: {
13
+ name: 'createdTime',
14
+ type: 'date',
15
+ displayName: 'Created'
16
+ },
17
+ ...Col.compactDate
18
+ };
19
+
12
20
  export const isOpen: ColumnSpec = {
13
21
  field: {name: 'isOpen', type: 'bool'},
14
22
  headerName: '',
@@ -29,23 +37,14 @@ export const key: ColumnSpec = {
29
37
  width: 160
30
38
  };
31
39
 
32
- export const createdTime: ColumnSpec = {
40
+ export const lastReceivedTime: ColumnSpec = {
33
41
  field: {
34
- name: 'createdTime',
42
+ name: 'lastReceivedTime',
35
43
  type: 'date',
36
- displayName: 'Created'
37
- },
38
- ...Col.compactDate
39
- };
40
-
41
- export const sentMessageCount: ColumnSpec = {
42
- field: {
43
- name: 'sentMessageCount',
44
- type: 'int',
45
- displayName: 'Sent'
44
+ displayName: 'Last Received'
46
45
  },
47
- ...Col.number,
48
- width: 90
46
+ ...Col.compactDate,
47
+ width: 140
49
48
  };
50
49
 
51
50
  export const lastSentTime: ColumnSpec = {
@@ -68,44 +67,12 @@ export const receivedMessageCount: ColumnSpec = {
68
67
  width: 90
69
68
  };
70
69
 
71
- export const lastReceivedTime: ColumnSpec = {
72
- field: {
73
- name: 'lastReceivedTime',
74
- type: 'date',
75
- displayName: 'Last Received'
76
- },
77
- ...Col.compactDate,
78
- width: 140
79
- };
80
-
81
- export const appVersion: ColumnSpec = {
82
- field: {
83
- name: 'appVersion',
84
- displayName: 'Version',
85
- type: 'string'
86
- },
87
- width: 120
88
- };
89
-
90
- export const appBuild: ColumnSpec = {
91
- field: {
92
- name: 'appBuild',
93
- displayName: 'Build',
94
- type: 'string'
95
- },
96
- width: 120
97
- };
98
- export const loadId: ColumnSpec = {
99
- field: {
100
- name: 'loadId',
101
- type: 'string'
102
- },
103
- ...badgeCol
104
- };
105
- export const tabId: ColumnSpec = {
70
+ export const sentMessageCount: ColumnSpec = {
106
71
  field: {
107
- name: 'tabId',
108
- type: 'string'
72
+ name: 'sentMessageCount',
73
+ type: 'int',
74
+ displayName: 'Sent'
109
75
  },
110
- ...badgeCol
76
+ ...Col.number,
77
+ width: 90
111
78
  };
@@ -11,15 +11,29 @@ import {dateTimeRenderer} from '@xh/hoist/format';
11
11
  import {Icon} from '@xh/hoist/icon';
12
12
  import copy from 'clipboard-copy';
13
13
 
14
- export const name: ColumnSpec = {
15
- field: {name: 'name', type: 'string'},
16
- width: 200
14
+ export const badgeCol: ColumnSpec = {
15
+ autosizable: false,
16
+ width: 100,
17
+ renderer: badgeRenderer
17
18
  };
18
19
 
19
- export const type: ColumnSpec = {
20
- field: {name: 'type', type: 'string'},
21
- width: 100
22
- };
20
+ export function badgeRenderer(v) {
21
+ return v
22
+ ? badge({
23
+ item: v,
24
+ className: 'xh-badge-col',
25
+ style: {cursor: 'copy'},
26
+ title: 'Double-click to copy',
27
+ onDoubleClick: () => {
28
+ copy(v);
29
+ XH.toast({
30
+ icon: Icon.copy(),
31
+ message: `Copied ${v}`
32
+ });
33
+ }
34
+ })
35
+ : '-';
36
+ }
23
37
 
24
38
  export const description: ColumnSpec = {
25
39
  field: {name: 'description', type: 'string'},
@@ -27,11 +41,9 @@ export const description: ColumnSpec = {
27
41
  minWidth: 200
28
42
  };
29
43
 
30
- export const notes: ColumnSpec = {
31
- field: {name: 'notes', type: 'string'},
32
- minWidth: 60,
33
- flex: true,
34
- tooltip: true
44
+ export const name: ColumnSpec = {
45
+ field: {name: 'name', type: 'string'},
46
+ width: 200
35
47
  };
36
48
 
37
49
  export const note: ColumnSpec = {
@@ -45,33 +57,20 @@ export const note: ColumnSpec = {
45
57
  tooltip: true
46
58
  };
47
59
 
60
+ export const notes: ColumnSpec = {
61
+ field: {name: 'notes', type: 'string'},
62
+ minWidth: 60,
63
+ flex: true,
64
+ tooltip: true
65
+ };
66
+
48
67
  export const timestampNoYear: ColumnSpec = {
49
68
  field: {name: 'timestamp', type: 'date'},
50
69
  ...dateTimeSec,
51
70
  renderer: dateTimeRenderer({fmt: 'MMM DD HH:mm:ss.SSS'})
52
71
  };
53
72
 
54
- export function badgeRenderer(v) {
55
- return v
56
- ? badge({
57
- item: v,
58
- className: 'xh-font-family-mono',
59
- style: {cursor: 'copy'},
60
- intent: 'primary',
61
- title: 'Double-click to copy',
62
- onDoubleClick: () => {
63
- copy(v);
64
- XH.toast({
65
- icon: Icon.copy(),
66
- message: `Copied ${v}`
67
- });
68
- }
69
- })
70
- : '-';
71
- }
72
-
73
- export const badgeCol: ColumnSpec = {
74
- autosizable: false,
75
- width: 90,
76
- renderer: badgeRenderer
73
+ export const type: ColumnSpec = {
74
+ field: {name: 'type', type: 'string'},
75
+ width: 100
77
76
  };
@@ -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
@@ -4,12 +4,23 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {badgeRenderer} from '@xh/hoist/admin/columns';
7
+ 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';
15
+
16
+ export const appBuild: ColumnSpec = {
17
+ field: {
18
+ name: 'appBuild',
19
+ displayName: 'Build',
20
+ type: 'string'
21
+ },
22
+ width: 120
23
+ };
13
24
 
14
25
  export const appEnvironment: ColumnSpec = {
15
26
  field: {
@@ -21,8 +32,12 @@ export const appEnvironment: ColumnSpec = {
21
32
  };
22
33
 
23
34
  export const appVersion: ColumnSpec = {
24
- field: {name: 'appVersion', type: 'string'},
25
- width: 130
35
+ field: {
36
+ name: 'appVersion',
37
+ displayName: 'Version',
38
+ type: 'string'
39
+ },
40
+ width: 120
26
41
  };
27
42
 
28
43
  export const browser: ColumnSpec = {
@@ -35,24 +50,25 @@ export const browser: ColumnSpec = {
35
50
  width: 100
36
51
  };
37
52
 
38
- export const severity: ColumnSpec = {
53
+ export const category: ColumnSpec = {
39
54
  field: {
40
- name: 'severity',
55
+ name: 'category',
41
56
  type: 'string',
42
57
  isDimension: true,
43
58
  aggregator: 'UNIQUE'
44
59
  },
45
- width: 80
60
+ width: 100
46
61
  };
47
62
 
48
- export const category: ColumnSpec = {
63
+ export const correlationId: ColumnSpec = {
49
64
  field: {
50
- name: 'category',
65
+ name: 'correlationId',
51
66
  type: 'string',
52
- isDimension: true,
53
- aggregator: 'UNIQUE'
67
+ displayName: 'Correlation ID'
54
68
  },
55
- width: 100
69
+ renderer: badgeRenderer,
70
+ width: 180,
71
+ autosizeBufferPx: 20
56
72
  };
57
73
 
58
74
  export const data: ColumnSpec = {
@@ -71,6 +87,20 @@ export const day: ColumnSpec = {
71
87
  displayName: 'App Day'
72
88
  };
73
89
 
90
+ export const dayRange: ColumnSpec = {
91
+ field: {
92
+ name: 'dayRange',
93
+ type: 'json',
94
+ aggregator: new RangeAggregator(),
95
+ displayName: 'App Day Range'
96
+ },
97
+ align: 'right',
98
+ width: 200,
99
+ renderer: dayRangeRenderer,
100
+ exportValue: dayRangeRenderer,
101
+ comparator: dayRangeComparator
102
+ };
103
+
74
104
  export const device: ColumnSpec = {
75
105
  field: {
76
106
  name: 'device',
@@ -81,6 +111,32 @@ export const device: ColumnSpec = {
81
111
  width: 100
82
112
  };
83
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
+
84
140
  export const elapsed: ColumnSpec = {
85
141
  field: {
86
142
  name: 'elapsed',
@@ -117,24 +173,33 @@ export const entryId: ColumnSpec = {
117
173
  align: 'right'
118
174
  };
119
175
 
120
- export const correlationId: ColumnSpec = {
176
+ export const error: ColumnSpec = {
121
177
  field: {
122
- name: 'correlationId',
178
+ name: 'error',
179
+ type: 'string'
180
+ },
181
+ width: 250,
182
+ autosizeMaxWidth: 400,
183
+ renderer: e => fmtSpan(e, {className: 'xh-font-family-mono xh-font-size-small'})
184
+ };
185
+
186
+ export const instance: ColumnSpec = {
187
+ field: {
188
+ name: 'instance',
123
189
  type: 'string',
124
- displayName: 'Correlation ID'
190
+ isDimension: true,
191
+ aggregator: 'UNIQUE'
125
192
  },
126
193
  renderer: badgeRenderer,
127
194
  width: 100
128
195
  };
129
196
 
130
- export const error: ColumnSpec = {
197
+ export const loadId: ColumnSpec = {
131
198
  field: {
132
- name: 'error',
199
+ name: 'loadId',
133
200
  type: 'string'
134
201
  },
135
- width: 250,
136
- autosizeMaxWidth: 400,
137
- renderer: e => fmtSpan(e, {className: 'xh-font-family-mono xh-font-size-small'})
202
+ ...badgeCol
138
203
  };
139
204
 
140
205
  export const msg: ColumnSpec = {
@@ -149,6 +214,52 @@ export const msg: ColumnSpec = {
149
214
  autosizeMaxWidth: 400
150
215
  };
151
216
 
217
+ export const severity: ColumnSpec = {
218
+ field: {
219
+ name: 'severity',
220
+ type: 'string',
221
+ isDimension: true,
222
+ aggregator: 'UNIQUE'
223
+ },
224
+ width: 80
225
+ };
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
+
255
+ export const tabId: ColumnSpec = {
256
+ field: {
257
+ name: 'tabId',
258
+ type: 'string'
259
+ },
260
+ ...badgeCol
261
+ };
262
+
152
263
  export const url: ColumnSpec = {
153
264
  field: {
154
265
  name: 'url',
@@ -159,15 +270,20 @@ export const url: ColumnSpec = {
159
270
  autosizeMaxWidth: 400
160
271
  };
161
272
 
162
- export const instance: ColumnSpec = {
163
- field: {
164
- name: 'instance',
165
- type: 'string',
166
- isDimension: true,
167
- aggregator: 'UNIQUE'
168
- },
169
- renderer: badgeRenderer,
170
- width: 100
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
+ }
171
287
  };
172
288
 
173
289
  export const userAgent: ColumnSpec = {
@@ -207,20 +323,6 @@ export const userMessageFlag: ColumnSpec = {
207
323
  }
208
324
  };
209
325
 
210
- export const dayRange: ColumnSpec = {
211
- field: {
212
- name: 'dayRange',
213
- type: 'json',
214
- aggregator: new RangeAggregator(),
215
- displayName: 'App Day Range'
216
- },
217
- align: 'right',
218
- width: 200,
219
- renderer: dayRangeRenderer,
220
- exportValue: dayRangeRenderer,
221
- comparator: dayRangeComparator
222
- };
223
-
224
326
  //-----------------------
225
327
  // Implementation
226
328
  //-----------------------
@@ -1,3 +1,4 @@
1
+ export * from './Clients';
1
2
  export * from './Core';
2
3
  export * from './Rest';
3
4
  export * from './Tracking';
@@ -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 {