@xh/hoist 73.0.0-SNAPSHOT.1745973083869 → 73.0.0-SNAPSHOT.1745976013413
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 +2 -0
- package/admin/AdminUtils.ts +0 -5
- package/admin/AppModel.ts +5 -17
- package/admin/tabs/activity/tracking/ActivityTracking.scss +0 -18
- package/admin/tabs/activity/tracking/ActivityTrackingModel.ts +199 -296
- package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +51 -81
- package/admin/tabs/activity/tracking/charts/ChartsModel.ts +218 -0
- package/admin/tabs/activity/tracking/charts/ChartsPanel.ts +76 -0
- package/admin/tabs/activity/tracking/detail/ActivityDetailModel.ts +59 -114
- package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +30 -61
- package/admin/tabs/cluster/instances/memory/MemoryMonitorModel.ts +2 -1
- package/build/types/admin/AdminUtils.d.ts +0 -2
- package/build/types/admin/AppModel.d.ts +1 -4
- package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +26 -30
- package/build/types/admin/tabs/activity/tracking/charts/ChartsModel.d.ts +34 -0
- package/build/types/admin/tabs/activity/tracking/charts/ChartsPanel.d.ts +2 -0
- package/build/types/admin/tabs/activity/tracking/detail/ActivityDetailModel.d.ts +1 -13
- package/build/types/cmp/form/FormModel.d.ts +40 -17
- package/build/types/cmp/form/field/SubformsFieldModel.d.ts +18 -20
- package/build/types/core/HoistBase.d.ts +2 -2
- package/build/types/data/cube/CubeField.d.ts +5 -4
- 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 +112 -20
- package/cmp/form/field/SubformsFieldModel.ts +22 -28
- package/cmp/grid/impl/GridHScrollbar.ts +2 -1
- package/core/HoistBase.ts +12 -12
- package/data/cube/CubeField.ts +18 -17
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/admin/tabs/activity/tracking/chart/AggChartModel.ts +0 -218
- package/admin/tabs/activity/tracking/chart/AggChartPanel.ts +0 -61
- package/admin/tabs/activity/tracking/datafields/DataFieldsEditor.ts +0 -147
- package/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.ts +0 -133
- package/build/types/admin/tabs/activity/tracking/chart/AggChartModel.d.ts +0 -33
- package/build/types/admin/tabs/activity/tracking/chart/AggChartPanel.d.ts +0 -2
- package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditor.d.ts +0 -2
- package/build/types/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel.d.ts +0 -46
|
@@ -4,24 +4,22 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {dataFieldsEditor} from '@xh/hoist/admin/tabs/activity/tracking/datafields/DataFieldsEditor';
|
|
8
|
-
import {errorMessage} from '@xh/hoist/cmp/error';
|
|
9
7
|
import {form} from '@xh/hoist/cmp/form';
|
|
10
8
|
import {grid} from '@xh/hoist/cmp/grid';
|
|
11
|
-
import {div,
|
|
9
|
+
import {div, hframe} from '@xh/hoist/cmp/layout';
|
|
12
10
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
13
11
|
import {button, buttonGroup, colChooserButton, exportButton} from '@xh/hoist/desktop/cmp/button';
|
|
12
|
+
import {errorMessage} from '@xh/hoist/cmp/error';
|
|
14
13
|
import {filterChooser} from '@xh/hoist/desktop/cmp/filter';
|
|
15
14
|
import {formField} from '@xh/hoist/desktop/cmp/form';
|
|
16
15
|
import {groupingChooser} from '@xh/hoist/desktop/cmp/grouping';
|
|
17
16
|
import {dateInput, DateInputProps, select} from '@xh/hoist/desktop/cmp/input';
|
|
18
17
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
19
18
|
import {toolbar, toolbarSep} from '@xh/hoist/desktop/cmp/toolbar';
|
|
20
|
-
import {viewManager} from '@xh/hoist/desktop/cmp/viewmanager';
|
|
21
19
|
import {Icon} from '@xh/hoist/icon';
|
|
22
20
|
import {LocalDate} from '@xh/hoist/utils/datetime';
|
|
23
21
|
import {ActivityTrackingModel} from './ActivityTrackingModel';
|
|
24
|
-
import {
|
|
22
|
+
import {chartsPanel} from './charts/ChartsPanel';
|
|
25
23
|
import {activityDetailView} from './detail/ActivityDetailView';
|
|
26
24
|
import './ActivityTracking.scss';
|
|
27
25
|
|
|
@@ -38,20 +36,14 @@ export const activityTrackingPanel = hoistCmp.factory({
|
|
|
38
36
|
return panel({
|
|
39
37
|
className: 'xh-admin-activity-panel',
|
|
40
38
|
tbar: tbar(),
|
|
41
|
-
|
|
39
|
+
item: hframe(aggregateView(), activityDetailView({flex: 1})),
|
|
42
40
|
mask: 'onLoad'
|
|
43
41
|
});
|
|
44
42
|
}
|
|
45
43
|
});
|
|
46
44
|
|
|
47
45
|
const tbar = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
48
|
-
const dateBtn = {outlined: true, width: 40} as const;
|
|
49
46
|
return toolbar(
|
|
50
|
-
viewManager({
|
|
51
|
-
model: model.viewManagerModel,
|
|
52
|
-
showSaveButton: 'always'
|
|
53
|
-
}),
|
|
54
|
-
'-',
|
|
55
47
|
form({
|
|
56
48
|
fieldDefaults: {label: null},
|
|
57
49
|
items: [
|
|
@@ -73,96 +65,74 @@ const tbar = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
|
73
65
|
onClick: () => model.adjustDates('add'),
|
|
74
66
|
disabled: model.endDay >= LocalDate.currentAppDay()
|
|
75
67
|
}),
|
|
76
|
-
buttonGroup(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
68
|
+
buttonGroup(
|
|
69
|
+
button({
|
|
70
|
+
text: '6m',
|
|
71
|
+
outlined: true,
|
|
72
|
+
width: 40,
|
|
73
|
+
onClick: () => model.adjustStartDate(6, 'months'),
|
|
74
|
+
active: model.isInterval(6, 'months')
|
|
75
|
+
}),
|
|
76
|
+
button({
|
|
77
|
+
text: '1m',
|
|
78
|
+
outlined: true,
|
|
79
|
+
width: 40,
|
|
80
|
+
onClick: () => model.adjustStartDate(1, 'months'),
|
|
81
|
+
active: model.isInterval(1, 'months')
|
|
82
|
+
}),
|
|
83
|
+
button({
|
|
84
|
+
text: '7d',
|
|
85
|
+
outlined: true,
|
|
86
|
+
width: 40,
|
|
87
|
+
onClick: () => model.adjustStartDate(7, 'days'),
|
|
88
|
+
active: model.isInterval(7, 'days')
|
|
89
|
+
}),
|
|
90
|
+
button({
|
|
91
|
+
text: '1d',
|
|
92
|
+
outlined: true,
|
|
93
|
+
width: 40,
|
|
94
|
+
onClick: () => model.adjustStartDate(1, 'days'),
|
|
95
|
+
active: model.isInterval(1, 'days')
|
|
96
|
+
})
|
|
97
|
+
),
|
|
104
98
|
toolbarSep(),
|
|
105
|
-
|
|
99
|
+
filterChooser({
|
|
100
|
+
flex: 1,
|
|
101
|
+
enableClear: true
|
|
102
|
+
}),
|
|
106
103
|
toolbarSep(),
|
|
107
|
-
dataFieldsEditor(),
|
|
108
|
-
filler(),
|
|
109
104
|
formField({
|
|
110
105
|
field: 'maxRows',
|
|
111
|
-
label: 'Max rows',
|
|
106
|
+
label: 'Max rows:',
|
|
112
107
|
width: 140,
|
|
113
108
|
item: select({
|
|
114
109
|
enableFilter: false,
|
|
115
110
|
hideDropdownIndicator: true,
|
|
116
111
|
options: model.maxRowOptions
|
|
117
112
|
})
|
|
113
|
+
}),
|
|
114
|
+
toolbarSep(),
|
|
115
|
+
button({
|
|
116
|
+
icon: Icon.reset(),
|
|
117
|
+
intent: 'danger',
|
|
118
|
+
title: 'Reset query to defaults',
|
|
119
|
+
onClick: () => model.resetQuery()
|
|
118
120
|
})
|
|
119
121
|
]
|
|
120
122
|
})
|
|
121
123
|
);
|
|
122
124
|
});
|
|
123
125
|
|
|
124
|
-
const filterChooserToggleButton = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
125
|
-
const {hasFilter, showFilterChooser} = model;
|
|
126
|
-
|
|
127
|
-
return button({
|
|
128
|
-
text: 'Filter',
|
|
129
|
-
icon: Icon.filter({prefix: hasFilter ? 'fas' : 'far'}),
|
|
130
|
-
intent: hasFilter ? 'primary' : null,
|
|
131
|
-
outlined: showFilterChooser,
|
|
132
|
-
onClick: () => model.toggleFilterChooser()
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const filterBar = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
137
|
-
return model.showFilterChooser
|
|
138
|
-
? toolbar(
|
|
139
|
-
filterChooser({
|
|
140
|
-
flex: 1,
|
|
141
|
-
enableClear: true
|
|
142
|
-
})
|
|
143
|
-
)
|
|
144
|
-
: null;
|
|
145
|
-
});
|
|
146
|
-
|
|
147
126
|
const aggregateView = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
148
127
|
return panel({
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
title: 'Aggregate Activity Report',
|
|
129
|
+
icon: Icon.users(),
|
|
151
130
|
compactHeader: true,
|
|
152
131
|
modelConfig: {
|
|
153
132
|
side: 'left',
|
|
154
|
-
defaultSize: 500
|
|
155
|
-
persistWith: {...model.persistWith, path: 'aggPanel'}
|
|
133
|
+
defaultSize: 500
|
|
156
134
|
},
|
|
157
|
-
tbar:
|
|
158
|
-
compact: true,
|
|
159
|
-
items: [
|
|
160
|
-
groupingChooser({flex: 1, maxWidth: 300}),
|
|
161
|
-
filler(),
|
|
162
|
-
colChooserButton(),
|
|
163
|
-
exportButton()
|
|
164
|
-
]
|
|
165
|
-
}),
|
|
135
|
+
tbar: [groupingChooser({flex: 1}), colChooserButton(), exportButton()],
|
|
166
136
|
items: [
|
|
167
137
|
grid({
|
|
168
138
|
flex: 1,
|
|
@@ -176,7 +146,7 @@ const aggregateView = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
|
|
|
176
146
|
],
|
|
177
147
|
omit: !model.maxRowsReached
|
|
178
148
|
}),
|
|
179
|
-
|
|
149
|
+
chartsPanel()
|
|
180
150
|
]
|
|
181
151
|
});
|
|
182
152
|
});
|
|
@@ -0,0 +1,218 @@
|
|
|
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
|
+
import {ChartModel} from '@xh/hoist/cmp/chart';
|
|
8
|
+
import {br, fragment} from '@xh/hoist/cmp/layout';
|
|
9
|
+
import {HoistModel, managed, lookup} from '@xh/hoist/core';
|
|
10
|
+
import {capitalizeWords, fmtDate} from '@xh/hoist/format';
|
|
11
|
+
import {bindable, makeObservable} from '@xh/hoist/mobx';
|
|
12
|
+
import {LocalDate} from '@xh/hoist/utils/datetime';
|
|
13
|
+
import {filter, sortBy, isEmpty} from 'lodash';
|
|
14
|
+
import moment from 'moment';
|
|
15
|
+
import {PanelModel} from '@xh/hoist/desktop/cmp/panel';
|
|
16
|
+
import {ActivityTrackingModel} from '../ActivityTrackingModel';
|
|
17
|
+
import {ONE_DAY} from '@xh/hoist/utils/datetime/DateTimeUtils';
|
|
18
|
+
|
|
19
|
+
export class ChartsModel extends HoistModel {
|
|
20
|
+
@managed panelModel = new PanelModel({
|
|
21
|
+
modalSupport: {width: '90vw', height: '60vh'},
|
|
22
|
+
side: 'bottom',
|
|
23
|
+
defaultSize: 370
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
@lookup(ActivityTrackingModel)
|
|
27
|
+
activityTrackingModel: ActivityTrackingModel;
|
|
28
|
+
|
|
29
|
+
/** metric to chart on Y axis - one of:
|
|
30
|
+
* + entryCount - count of total track log entries within the primary dim group.
|
|
31
|
+
* + count - count of unique secondary dim values within the primary dim group.
|
|
32
|
+
* + elapsed - avg elapsed time in ms for the primary dim group.
|
|
33
|
+
*/
|
|
34
|
+
@bindable
|
|
35
|
+
metric: 'entryCount' | 'count' | 'elapsed' = 'entryCount';
|
|
36
|
+
|
|
37
|
+
/** show weekends on the activity chart */
|
|
38
|
+
@bindable
|
|
39
|
+
incWeekends: boolean = false;
|
|
40
|
+
|
|
41
|
+
@managed
|
|
42
|
+
categoryChartModel: ChartModel = new ChartModel({
|
|
43
|
+
highchartsConfig: {
|
|
44
|
+
chart: {type: 'column', animation: false},
|
|
45
|
+
plotOptions: {column: {animation: false}},
|
|
46
|
+
legend: {enabled: false},
|
|
47
|
+
title: {text: null},
|
|
48
|
+
xAxis: {type: 'category', title: {}},
|
|
49
|
+
yAxis: [{title: {text: null}, allowDecimals: false}]
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
@managed
|
|
54
|
+
timeseriesChartModel: ChartModel = new ChartModel({
|
|
55
|
+
highchartsConfig: {
|
|
56
|
+
chart: {type: 'line', animation: false},
|
|
57
|
+
plotOptions: {
|
|
58
|
+
line: {
|
|
59
|
+
events: {
|
|
60
|
+
click: e => this.selectRow(e)
|
|
61
|
+
},
|
|
62
|
+
width: 1,
|
|
63
|
+
animation: false,
|
|
64
|
+
step: 'left'
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
legend: {enabled: false},
|
|
68
|
+
title: {text: null},
|
|
69
|
+
xAxis: {
|
|
70
|
+
type: 'datetime',
|
|
71
|
+
title: {},
|
|
72
|
+
units: [
|
|
73
|
+
['day', [1]],
|
|
74
|
+
['week', [2]],
|
|
75
|
+
['month', [1]]
|
|
76
|
+
],
|
|
77
|
+
labels: {
|
|
78
|
+
formatter: function () {
|
|
79
|
+
return fmtDate(this.value, 'D MMM');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
yAxis: [{title: {text: null}, allowDecimals: false}]
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
get showAsTimeseries(): boolean {
|
|
88
|
+
return this.dimensions[0] === 'day';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get chartModel(): ChartModel {
|
|
92
|
+
return this.showAsTimeseries ? this.timeseriesChartModel : this.categoryChartModel;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get primaryDim(): string {
|
|
96
|
+
return this.dimensions[0];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get secondaryDim(): string {
|
|
100
|
+
const {dimensions} = this;
|
|
101
|
+
return dimensions.length >= 2 ? dimensions[1] : null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get data() {
|
|
105
|
+
const roots = this.activityTrackingModel.gridModel.store.allRootRecords;
|
|
106
|
+
return roots.length ? roots[0].children : [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get dimensions() {
|
|
110
|
+
return this.activityTrackingModel.dimensions;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
constructor() {
|
|
114
|
+
super();
|
|
115
|
+
makeObservable(this);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getLabelForMetric(metric, multiline) {
|
|
119
|
+
switch (metric) {
|
|
120
|
+
case 'count':
|
|
121
|
+
return multiline
|
|
122
|
+
? fragment(`Unique`, br(), `${this.getUnitsForDim(this.secondaryDim)} Count`)
|
|
123
|
+
: `Unique ${this.getUnitsForDim(this.secondaryDim)} Count`;
|
|
124
|
+
case 'entryCount':
|
|
125
|
+
return multiline ? fragment('Total', br(), 'Entry Count') : 'Total Entry Count';
|
|
126
|
+
case 'elapsed':
|
|
127
|
+
return 'Elapsed ms';
|
|
128
|
+
default:
|
|
129
|
+
return '???';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//-----------------
|
|
134
|
+
// Implementation
|
|
135
|
+
//-----------------
|
|
136
|
+
|
|
137
|
+
private selectRow(e) {
|
|
138
|
+
const date = moment(e.point.x).format('YYYY-MM-DD'),
|
|
139
|
+
id = `root>>day=[${date}]`;
|
|
140
|
+
this.activityTrackingModel.gridModel.selectAsync(id);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
override onLinked() {
|
|
144
|
+
this.addReaction({
|
|
145
|
+
track: () => [this.data, this.metric, this.incWeekends],
|
|
146
|
+
run: () => this.loadChart()
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private loadChart() {
|
|
151
|
+
const {showAsTimeseries, chartModel, primaryDim} = this,
|
|
152
|
+
series = this.getSeriesData();
|
|
153
|
+
|
|
154
|
+
if (!showAsTimeseries) {
|
|
155
|
+
chartModel.updateHighchartsConfig({
|
|
156
|
+
xAxis: {title: {text: this.getUnitsForDim(primaryDim)}}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
chartModel.setSeries(series);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private getSeriesData() {
|
|
164
|
+
const {data, metric, primaryDim, showAsTimeseries} = this,
|
|
165
|
+
metricLabel = this.getLabelForMetric(metric, false);
|
|
166
|
+
let sortedData = sortBy(data, aggRow => {
|
|
167
|
+
const {cubeLabel} = aggRow.data;
|
|
168
|
+
switch (primaryDim) {
|
|
169
|
+
case 'day':
|
|
170
|
+
return LocalDate.from(cubeLabel).timestamp;
|
|
171
|
+
case 'month':
|
|
172
|
+
return moment(cubeLabel, 'MMM YYYY').valueOf();
|
|
173
|
+
default:
|
|
174
|
+
return cubeLabel;
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
177
|
+
chartData = sortedData.map(aggRow => {
|
|
178
|
+
const {cubeLabel} = aggRow.data,
|
|
179
|
+
xVal = showAsTimeseries ? LocalDate.from(cubeLabel).timestamp : cubeLabel,
|
|
180
|
+
yVal = Math.round(aggRow.data[metric]);
|
|
181
|
+
return [xVal, yVal];
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Insert data where no activity was logged
|
|
185
|
+
if (showAsTimeseries) {
|
|
186
|
+
const fillData = [];
|
|
187
|
+
for (let i = 1; i < chartData.length; i++) {
|
|
188
|
+
const skippedDayCount = Math.floor(
|
|
189
|
+
(chartData[i][0] - chartData[i - 1][0]) / ONE_DAY - 1
|
|
190
|
+
);
|
|
191
|
+
if (skippedDayCount > 0) {
|
|
192
|
+
for (let j = 1; j <= skippedDayCount; j++) {
|
|
193
|
+
const skippedDate = chartData[i - 1][0] + j * ONE_DAY;
|
|
194
|
+
fillData.push([skippedDate, 0]);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!isEmpty(fillData)) {
|
|
199
|
+
chartData.push(...fillData);
|
|
200
|
+
chartData = sortBy(chartData, data => data[0]);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!this.incWeekends) {
|
|
204
|
+
chartData = filter(chartData, data => LocalDate.from(data[0]).isWeekday);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return [{name: metricLabel, data: chartData}];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private getUnitsForDim(dim) {
|
|
211
|
+
return (
|
|
212
|
+
{
|
|
213
|
+
username: 'User',
|
|
214
|
+
msg: 'Message'
|
|
215
|
+
}[dim] ?? capitalizeWords(dim)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
import {chart} from '@xh/hoist/cmp/chart';
|
|
8
|
+
import {hoistCmp, creates} from '@xh/hoist/core';
|
|
9
|
+
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
10
|
+
import {buttonGroupInput} from '@xh/hoist/desktop/cmp/input';
|
|
11
|
+
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
12
|
+
import {Icon} from '@xh/hoist/icon/Icon';
|
|
13
|
+
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
14
|
+
import {checkbox} from '@xh/hoist/desktop/cmp/input';
|
|
15
|
+
import {hspacer} from '@xh/hoist/cmp/layout';
|
|
16
|
+
import {ChartsModel} from './ChartsModel';
|
|
17
|
+
|
|
18
|
+
export const chartsPanel = hoistCmp.factory({
|
|
19
|
+
model: creates(ChartsModel),
|
|
20
|
+
render({model, ...props}) {
|
|
21
|
+
const {chartModel, activityTrackingModel, panelModel} = model,
|
|
22
|
+
{isModal} = panelModel;
|
|
23
|
+
return panel({
|
|
24
|
+
title: !isModal ? 'Aggregate Activity Chart' : activityTrackingModel.queryDisplayString,
|
|
25
|
+
icon: Icon.chartBar(),
|
|
26
|
+
model: panelModel,
|
|
27
|
+
compactHeader: !isModal,
|
|
28
|
+
item: chart({model: chartModel}),
|
|
29
|
+
bbar: bbar(),
|
|
30
|
+
height: '100%',
|
|
31
|
+
...props
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const bbar = hoistCmp.factory<ChartsModel>(() =>
|
|
37
|
+
toolbar(metricSwitcher({multiline: true}), hspacer(), incWeekendsCheckbox())
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const incWeekendsCheckbox = hoistCmp.factory<ChartsModel>(({model}) =>
|
|
41
|
+
checkbox({
|
|
42
|
+
omit: !model.showAsTimeseries,
|
|
43
|
+
bind: 'incWeekends',
|
|
44
|
+
label: 'Inc Wknds'
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const metricSwitcher = hoistCmp.factory<ChartsModel>(({model, multiline}) => {
|
|
49
|
+
return buttonGroupInput({
|
|
50
|
+
className: 'xh-admin-activity-panel__metric-switcher',
|
|
51
|
+
bind: 'metric',
|
|
52
|
+
outlined: true,
|
|
53
|
+
flex: 2,
|
|
54
|
+
items: [
|
|
55
|
+
button({
|
|
56
|
+
text: model.getLabelForMetric('entryCount', multiline),
|
|
57
|
+
value: 'entryCount',
|
|
58
|
+
outlined: true,
|
|
59
|
+
flex: 1
|
|
60
|
+
}),
|
|
61
|
+
button({
|
|
62
|
+
text: model.getLabelForMetric('count', multiline),
|
|
63
|
+
value: 'count',
|
|
64
|
+
outlined: true,
|
|
65
|
+
flex: 1,
|
|
66
|
+
omit: !model.secondaryDim
|
|
67
|
+
}),
|
|
68
|
+
button({
|
|
69
|
+
text: model.getLabelForMetric('elapsed', multiline),
|
|
70
|
+
value: 'elapsed',
|
|
71
|
+
outlined: true,
|
|
72
|
+
flex: 1
|
|
73
|
+
})
|
|
74
|
+
]
|
|
75
|
+
});
|
|
76
|
+
});
|