1
1
<template lang="pug">
2
2
div.mx-3
3
3
b-form
4
- b-form-group( label ="Bucket :" )
5
- select( v-model ="selectedBucket " )
6
- option( v-for ="bucket in buckets" , :value ="bucket.id " ) {{ bucket.id }}
4
+ b-form-group( label ="Host :" )
5
+ select( v-model ="selectedHost " )
6
+ option( v-for ="host in hostnames" : value= "host " ) {{ host }}
7
7
b-form-group( label ="Show:" )
8
8
select( v-model ="view" )
9
9
option( value ="timeGridDay" ) Day
@@ -15,26 +15,38 @@ div.mx-3
15
15
</template >
16
16
17
17
<script >
18
- import { getTitleAttr , getColorFromString } from ' ../util/color' ;
19
18
import moment from ' moment' ;
20
19
import _ from ' lodash' ;
21
20
import FullCalendar from ' @fullcalendar/vue' ;
22
21
import timeGridPlugin from ' @fullcalendar/timegrid' ;
23
22
23
+ import queries from ' ~/queries' ;
24
+ import { getTitleAttr , getColorFromString } from ' ../util/color' ;
25
+ import { useCategoryStore } from ' ~/stores/categories' ;
26
+
24
27
// TODO: Use canonical timeline query, with flooding and categorization
25
28
// TODO: Checkbox for toggling category-view, where adjacent events with same category are merged and the events are labeled by category
26
29
// TODO: Use the recommended way of dynamically getting events: https://fullcalendar.io/docs/events-function
27
30
export default {
28
31
components: {
29
- FullCalendar, // make the <FullCalendar> tag available
32
+ FullCalendar,
30
33
},
31
34
props: {
32
35
buckets: { type: Array },
33
36
},
34
37
data () {
35
- return { fitToActive: false , selectedBucket: null , view: ' timeGridDay' };
38
+ return {
39
+ events: [],
40
+ fitToActive: false ,
41
+ selectedHost: ' erb-m2.localdomain' ,
42
+ view: ' timeGridWeek' ,
43
+ };
36
44
},
37
45
computed: {
46
+ hostnames : function () {
47
+ if (this .buckets == null ) return [];
48
+ return _ .uniq (this .buckets .map (b => b .hostname ).filter (h => h != null ));
49
+ },
38
50
calendarOptions : function () {
39
51
const events = this .events ;
40
52
const first = _ .minBy (events, e => e .start );
@@ -67,7 +79,108 @@ export default {
67
79
},
68
80
};
69
81
},
70
- events : function () {
82
+ queryOptions : function () {
83
+ return {
84
+ hostname: this .selectedHost ,
85
+ filter_afk: true ,
86
+ start: moment ().startOf (' week' ).format (),
87
+ stop: moment ().endOf (' week' ).format (),
88
+ };
89
+ },
90
+ },
91
+ watch: {
92
+ view : function (to ) {
93
+ const calendar = this .$refs .fullCalendar .getApi ();
94
+ calendar .changeView (to);
95
+ },
96
+ selectedHost : async function () {
97
+ console .log (' selectedHost changed' );
98
+ this .events = await this .loadEventsCanonical ();
99
+ },
100
+ },
101
+ mounted : async function () {
102
+ this .events = await this .loadEventsCanonical ();
103
+ },
104
+ methods: {
105
+ onEventClick : function (arg ) {
106
+ // TODO: Open event inspector/editor here
107
+ alert (' event click! ' + JSON .stringify (arg .event ));
108
+ },
109
+ loadEventsCanonical : async function () {
110
+ console .log (' loadEventsCanonical' );
111
+ console .log (this .queryOptions .hostname );
112
+ if (this .queryOptions .hostname == null ) return [];
113
+
114
+ const categoryStore = useCategoryStore ();
115
+ categoryStore .load ();
116
+ const categories = categoryStore .classes_for_query ;
117
+
118
+ let query = queries .canonicalEvents ({
119
+ bid_window: ' aw-watcher-window_' + this .queryOptions .hostname ,
120
+ bid_afk: ' aw-watcher-afk_' + this .queryOptions .hostname ,
121
+ filter_afk: this .queryOptions .filter_afk ,
122
+ categories,
123
+ });
124
+ query += ' RETURN = events;' ;
125
+ console .log (query);
126
+ query = query .split (' ;' ).map (s => s .trim () + ' ;' );
127
+
128
+ const timeperiods = [
129
+ moment (this .queryOptions .start ).format () + ' /' + moment (this .queryOptions .stop ).format (),
130
+ ];
131
+ console .log (' Querying' );
132
+ const data = await this .$aw .query (timeperiods, query);
133
+ console .log (data);
134
+ let events = _ .orderBy (data[0 ], [' timestamp' ], [' desc' ]);
135
+ console .log (' events' , events);
136
+
137
+ // process events, merging adjacent events with same category
138
+ const mergedEvents = [];
139
+ let lastEvent = null ;
140
+ for (let i = 0 ; i < events .length ; i++ ) {
141
+ const event = events[i];
142
+ if (lastEvent == null ) {
143
+ lastEvent = event ;
144
+ continue ;
145
+ }
146
+ // if adjacent with less than 10 seconds between, merge
147
+ const isAdjacent =
148
+ moment (event .timestamp ).diff (
149
+ moment (lastEvent .timestamp ).add (lastEvent .duration , ' seconds' ),
150
+ ' seconds'
151
+ ) < 10 ;
152
+ if (
153
+ isAdjacent &&
154
+ event .data [' $category' ].join (' > ' ) == lastEvent .data [' $category' ].join (' > ' )
155
+ ) {
156
+ lastEvent .duration += event .duration ;
157
+ } else {
158
+ mergedEvents .push (lastEvent);
159
+ lastEvent = event ;
160
+ }
161
+ }
162
+ if (lastEvent != null ) mergedEvents .push (lastEvent);
163
+
164
+ console .log (mergedEvents);
165
+
166
+ events = _ .filter (mergedEvents, e => e .duration > 60 );
167
+ const bucket = {
168
+ id: ' Canonical' ,
169
+ hostname: this .queryOptions .hostname ,
170
+ type: ' currentwindow' ,
171
+ };
172
+ events = _ .map (events, e => {
173
+ return {
174
+ title: e .data [' $category' ].join (' > ' ),
175
+ start: moment (e .timestamp ).format (),
176
+ end: moment (e .timestamp ).add (e .duration , ' seconds' ).format (),
177
+ // TODO: this isn't the correct way to get the category color
178
+ backgroundColor: getColorFromString (e .data [' $category' ].join (' > ' )),
179
+ };
180
+ });
181
+ return events;
182
+ },
183
+ loadEventsBucket : function () {
71
184
// NOTE: This returns FullCalendar events, not ActivityWatch events.
72
185
if (this .buckets == null ) return [];
73
186
@@ -88,17 +201,5 @@ export default {
88
201
return events;
89
202
},
90
203
},
91
- watch: {
92
- view : function (to ) {
93
- const calendar = this .$refs .fullCalendar .getApi ();
94
- calendar .changeView (to);
95
- },
96
- },
97
- methods: {
98
- onEventClick : function (arg ) {
99
- // TODO: Open event inspector/editor here
100
- alert (' event click! ' + JSON .stringify (arg .event ));
101
- },
102
- },
103
204
};
104
205
</script >
0 commit comments