@@ -719,11 +719,23 @@ <h2>Service Status</h2>
719719 </ tbody >
720720 </ table >
721721 </ div >
722- < h3 > Review Counts (6-hour buckets)</ h3 >
722+ < div style ="display: flex; align-items: center; gap: 15px; ">
723+ < h3 style ="margin: 0; "> Review Counts</ h3 >
724+ < label style ="display: flex; align-items: center; gap: 6px; font-size: 14px; ">
725+ Bucket size:
726+ < select id ="bucketSize " onchange ="applyFilterAndUpdateDisplay() " style ="padding: 4px 8px; ">
727+ < option value ="3 "> 3h</ option >
728+ < option value ="6 "> 6h</ option >
729+ < option value ="12 "> 12h</ option >
730+ < option value ="24 " selected > 24h</ option >
731+ < option value ="48 "> 48h</ option >
732+ </ select >
733+ </ label >
734+ </ div >
723735 < div class ="chart-container ">
724736 < canvas id ="reviewChart "> </ canvas >
725737 </ div >
726- < h3 style ="margin-top: 40px; "> Daily Averages (by feedback status)</ h3 >
738+ < h3 style ="margin-top: 40px; "> Cost and Time (by feedback status)</ h3 >
727739 < div class ="chart-container ">
728740 < canvas id ="averagesChart "> </ canvas >
729741 </ div >
@@ -1230,18 +1242,17 @@ <h3 style="margin-top: 40px;">Feedback Breakdown (36-hour rolling)</h3>
12301242 // Check if any review has cost data (indicates superuser)
12311243 const hasCostData = reviews . some ( r => r . cost_usd !== undefined ) ;
12321244
1233- // Group reviews by 6-hour time buckets and status
1245+ const bucketSize = parseInt ( document . getElementById ( 'bucketSize' ) . value ) ;
1246+
1247+ // Group reviews by time buckets and status
12341248 const dataByBucket = { } ;
12351249
12361250 reviews . forEach ( review => {
1237- // Parse date and round to nearest 6-hour bucket
1251+ // Parse date and round to nearest bucket
12381252 const timestamp = parseUTCDate ( review . date ) ;
1239- const hours = timestamp . getHours ( ) ;
1240- const bucketHour = Math . floor ( hours / 6 ) * 6 ; // 0, 6, 12, or 18
1241-
1242- // Create bucket key (ISO format with hour set to bucket start)
1243- timestamp . setHours ( bucketHour , 0 , 0 , 0 ) ;
1244- const bucketKey = timestamp . toISOString ( ) ;
1253+ const bucketMs = bucketSize * 3600000 ;
1254+ const bucketStart = new Date ( Math . floor ( timestamp . getTime ( ) / bucketMs ) * bucketMs ) ;
1255+ const bucketKey = bucketStart . toISOString ( ) ;
12451256
12461257 if ( ! dataByBucket [ bucketKey ] ) {
12471258 dataByBucket [ bucketKey ] = {
@@ -1267,7 +1278,7 @@ <h3 style="margin-top: 40px;">Feedback Breakdown (36-hour rolling)</h3>
12671278 }
12681279 } ) ;
12691280
1270- console . log ( ' Data by 6 -hour bucket:' , dataByBucket ) ;
1281+ console . log ( ` Data by ${ bucketSize } -hour bucket:` , dataByBucket ) ;
12711282
12721283 // Convert to sorted arrays, null for zero values (so lines aren't drawn)
12731284 const buckets = Object . keys ( dataByBucket ) . sort ( ) ;
@@ -1470,7 +1481,8 @@ <h3 style="margin-top: 40px;">Feedback Breakdown (36-hour rolling)</h3>
14701481 hasFeedback : review . has_feedback || false
14711482 } ) ) ;
14721483
1473- // Group reviews by day and calculate averages, separated by feedback status
1484+ // Group reviews by bucket and calculate averages, separated by feedback status
1485+ const bucketSize = parseInt ( document . getElementById ( 'bucketSize' ) . value ) ;
14741486 const dataByDay = { } ;
14751487
14761488 reviewsWithFeedback . forEach ( review => {
@@ -1479,10 +1491,11 @@ <h3 style="margin-top: 40px;">Feedback Breakdown (36-hour rolling)</h3>
14791491 return ;
14801492 }
14811493
1482- // Parse date and get day (midnight)
1494+ // Parse date and round to bucket
14831495 const timestamp = parseUTCDate ( review . date ) ;
1484- timestamp . setHours ( 0 , 0 , 0 , 0 ) ;
1485- const dayKey = timestamp . toISOString ( ) ;
1496+ const bucketMs = bucketSize * 3600000 ;
1497+ const bucketStart = new Date ( Math . floor ( timestamp . getTime ( ) / bucketMs ) * bucketMs ) ;
1498+ const dayKey = bucketStart . toISOString ( ) ;
14861499
14871500 if ( ! dataByDay [ dayKey ] ) {
14881501 dataByDay [ dayKey ] = {
0 commit comments