@@ -96,14 +96,14 @@ export default {
9696 categoryStore: useCategoryStore (),
9797 settingsStore: useSettingsStore (),
9898 bucketsStore: useBucketsStore (),
99-
100- selectedHosts: [], // Will be populated on mount
101- selectedCategories: [JSON .stringify ([' Work' ])], // Default to 'Work' category
99+
100+ selectedHosts: [], // Will be populated on mount
101+ selectedCategories: [JSON .stringify ([' Work' ])], // Default to 'Work' category
102102 breakTime: 5 ,
103103 dateRange: ' last7d' ,
104104 customStart: null ,
105105 customEnd: null ,
106-
106+
107107 loading: false ,
108108 dailyData: [] as DailyData [],
109109 rawData: {},
@@ -114,23 +114,23 @@ export default {
114114 // Get available hosts from window watcher buckets
115115 const allBuckets = this .bucketsStore .buckets || [];
116116 const windowBuckets = allBuckets .filter (b => b .type === ' currentwindow' );
117-
117+
118118 const hosts = windowBuckets .map (b => {
119119 // Extract hostname from bucket ID (format: aw-watcher-window_hostname)
120120 return b .id .replace (' aw-watcher-window_' , ' ' );
121121 });
122-
122+
123123 return hosts .map (host => ({
124124 value: host ,
125125 text: host ,
126126 }));
127127 },
128-
128+
129129 categoryOptions() {
130130 // Get all categories (not just those with rules) for the filter
131131 const cats = this .categoryStore .all_categories || [];
132132 return cats .map (cat => ({
133- value: JSON .stringify (cat ), // Store as JSON string to preserve array structure
133+ value: JSON .stringify (cat ), // Store as JSON string to preserve array structure
134134 text: cat .join (' > ' ),
135135 }));
136136 },
@@ -159,7 +159,7 @@ export default {
159159 async mounted() {
160160 this .categoryStore .load ();
161161 await this .bucketsStore .ensureLoaded ();
162-
162+
163163 // Auto-select all available hosts
164164 if (this .hostOptions .length > 0 ) {
165165 this .selectedHosts = this .hostOptions .map (opt => opt .value );
@@ -170,66 +170,68 @@ export default {
170170 this .loading = true ;
171171 try {
172172 const client = getClient ();
173-
173+
174174 if (this .selectedHosts .length === 0 ) {
175175 alert (' Please select at least one host' );
176176 this .loading = false ;
177177 return ;
178178 }
179-
179+
180180 // Get date range
181181 const timeperiods = this .getTimeperiods ();
182-
182+
183183 // Build query with flooding
184184 const breakTimeSeconds = this .breakTime * 60 ;
185185 // Parse categories back from JSON strings
186186 const categoriesFilter = this .selectedCategories .map (c => JSON .parse (c ));
187-
187+
188188 // Get categories for query
189189 const categories = this .categoryStore .classes_for_query ;
190190 const categoriesStr = JSON .stringify (categories ).replace (/ \\\\ / g , ' \\ ' );
191-
191+
192192 // Build multi-device query with custom flooding
193193 let query = ' ' ;
194-
194+
195195 // Query each host with custom flooding
196196 for (const hostname of this .selectedHosts ) {
197197 const safeHost = hostname .replace (/ [^ a-zA-Z0-9 _] / g , ' ' );
198198 query += `
199199 events_${safeHost } = flood(query_bucket(find_bucket("aw-watcher-window_${hostname }")), ${breakTimeSeconds });
200200 events_${safeHost } = categorize(events_${safeHost }, ${categoriesStr });
201- events_${safeHost } = filter_keyvals(events_${safeHost }, "$category", ${JSON .stringify (categoriesFilter )});
201+ events_${safeHost } = filter_keyvals(events_${safeHost }, "$category", ${JSON .stringify (
202+ categoriesFilter
203+ )});
202204 ` ;
203205 }
204-
206+
205207 // Combine events from all hosts using union_no_overlap
206208 query += ' \n events = [];' ;
207209 for (const hostname of this .selectedHosts ) {
208210 const safeHost = hostname .replace (/ [^ a-zA-Z0-9 _] / g , ' ' );
209211 query += ` \n events = union_no_overlap(events, events_${safeHost });` ;
210212 }
211-
213+
212214 query += `
213215 duration = sum_durations(events);
214216 RETURN = {"events": events, "duration": duration};
215217 ` ;
216-
218+
217219 // Debug: log the query
218220 console .log (' Query being sent:' , query );
219221 console .log (' Query length:' , query .length );
220-
222+
221223 // Query for each day
222224 const results = await client .query (timeperiods , [query ]);
223-
225+
224226 // Process results into daily data
225227 this .dailyData = timeperiods .map ((tp , i ) => {
226228 const result = results [i ];
227229 const events = result .events || [];
228230 const duration = result .duration || 0 ;
229-
231+
230232 // tp is a string like "2025-01-01T00:00:00Z/2025-01-02T00:00:00Z"
231233 const startDate = tp .split (' /' )[0 ];
232-
234+
233235 return {
234236 date: moment (startDate ).format (' YYYY-MM-DD' ),
235237 duration ,
@@ -238,7 +240,7 @@ export default {
238240 events ,
239241 };
240242 });
241-
243+
242244 this .rawData = results ;
243245 } catch (error ) {
244246 console .error (' Error loading work time data:' , error );
@@ -247,12 +249,12 @@ export default {
247249 this .loading = false ;
248250 }
249251 },
250-
252+
251253 getTimeperiods() {
252254 const offset = this .settingsStore .startOfDay ;
253-
255+
254256 const timeperiods = [];
255-
257+
256258 if (this .dateRange === ' last7d' ) {
257259 for (let i = 6 ; i >= 0 ; i -- ) {
258260 const start = moment ().subtract (i , ' days' ).startOf (' day' ).add (offset );
@@ -267,17 +269,17 @@ export default {
267269 }
268270 }
269271 // TODO: Add other date ranges
270-
272+
271273 return timeperiods ;
272274 },
273-
275+
274276 formatDuration(seconds : number ): string {
275277 if (! seconds ) return ' 0:00' ;
276278 const hours = Math .floor (seconds / 3600 );
277279 const minutes = Math .floor ((seconds % 3600 ) / 60 );
278280 return ` ${hours }:${minutes .toString ().padStart (2 , ' 0' )} ` ;
279281 },
280-
282+
281283 exportCSV() {
282284 const headers = [' Date' , ' Duration (hours)' , ' Sessions' , ' Avg Session (minutes)' ];
283285 const rows = this .dailyData .map (day => [
@@ -286,17 +288,19 @@ export default {
286288 day .sessions ,
287289 (day .avgSession / 60 ).toFixed (1 ),
288290 ]);
289-
291+
290292 const csv = [
291293 headers .join (' ,' ),
292294 ... rows .map (row => row .join (' ,' )),
293295 ' ' ,
294- ` Total,${(this .totalDuration / 3600 ).toFixed (2 )},${this .totalSessions },${(this .avgSessionLength / 60 ).toFixed (1 )} ` ,
296+ ` Total,${(this .totalDuration / 3600 ).toFixed (2 )},${this .totalSessions },${(
297+ this .avgSessionLength / 60
298+ ).toFixed (1 )} ` ,
295299 ].join (' \n ' );
296-
300+
297301 this .downloadFile (csv , ' work_time_report.csv' , ' text/csv' );
298302 },
299-
303+
300304 exportJSON() {
301305 const data = {
302306 parameters: {
@@ -312,11 +316,11 @@ export default {
312316 daily: this .dailyData ,
313317 rawEvents: this .rawData ,
314318 };
315-
319+
316320 const json = JSON .stringify (data , null , 2 );
317321 this .downloadFile (json , ' work_time_report.json' , ' application/json' );
318322 },
319-
323+
320324 downloadFile(content : string , filename : string , mimeType : string ) {
321325 const blob = new Blob ([content ], { type: mimeType });
322326 const url = URL .createObjectURL (blob );
0 commit comments