@@ -335,20 +335,45 @@ export const createIncidentsChartBars = (incident: Incident, dateArray: SpanDate
335335 warning : t_global_color_status_warning_default . var ,
336336 } ;
337337
338+ let prev = null ;
338339 for ( let i = 0 ; i < groupedData . length ; i ++ ) {
339340 const severity = getSeverityName ( groupedData [ i ] [ 2 ] ) ;
340341 const isLastElement = i === groupedData . length - 1 ;
342+ const isNodata = groupedData [ i ] [ 2 ] === 'nodata' ;
341343
342- // - To avoid certain edge cases the startDate should
343- // be the minimum between alert.firstTimestamp and groupedData[i][0]
344344 // - Round the result since groupedData comes from raw time series values.
345- // - We are considering only the first element of the groupedData (i === 0)
346- // because in the case of consecutive intervals (i.e. the incident changes priority)
347- // we want that the end of a bar is equal to the start of the next one
348- const startDate =
349- i === 0
350- ? roundTimestampToFiveMinutes ( Math . min ( incident . firstTimestamp , groupedData [ i ] [ 0 ] ) )
351- : groupedData [ i ] [ 0 ] ;
345+ let startDate = 0 ;
346+ if ( i === 0 ) {
347+ // - For the first bar, use the incident's first timestamp (rounded)
348+ // This represents when the incident actually started
349+ // If the first interval is 'nodata', we still use incident.firstTimestamp
350+ // as the absolute start, since 'nodata' at the beginning is just visualization
351+ // - Math.min is needed to handle edge cases when the incident is quite new and the firstTimestamp may be greater
352+ // than the aggregated data from the query_range
353+ startDate =
354+ roundTimestampToFiveMinutes ( Math . min ( incident . firstTimestamp , groupedData [ i ] [ 0 ] ) ) * 1000 ;
355+ } else {
356+ // For subsequent bars, only calculate startDate for non-nodata intervals
357+ // (nodata intervals don't need accurate startDate for tooltip display)
358+ if ( ! isNodata ) {
359+ if ( prev ) {
360+ // Calculate absolute start by:
361+ // Previous bar's absolute start + duration of previous bar + gap to current bar
362+ // This maintains continuity in the absolute timeline
363+ const prevBarDuration = prev . y . getTime ( ) - prev . startDate . getTime ( ) ;
364+ const gapToCurrent = groupedData [ i ] [ 0 ] * 1000 - prev . y . getTime ( ) ;
365+ startDate = prev . startDate . getTime ( ) + prevBarDuration + gapToCurrent ;
366+ } else {
367+ // If prev is null (e.g., first interval was 'nodata'), fall back to incident.firstTimestamp or first groupedData
368+ // This ensures we always have a valid absolute start time
369+ startDate = roundTimestampToFiveMinutes ( Math . min ( incident . firstTimestamp , groupedData [ i ] [ 0 ] ) ) * 1000 ;
370+ }
371+ } else {
372+ // For 'nodata' intervals, we can use the interval start timestamp
373+ // This is mainly for consistency, but won't be displayed in tooltips
374+ startDate = groupedData [ i ] [ 0 ] * 1000 ;
375+ }
376+ }
352377
353378 data . push ( {
354379 y0 : new Date ( groupedData [ i ] [ 0 ] * 1000 ) ,
@@ -359,14 +384,17 @@ export const createIncidentsChartBars = (incident: Incident, dateArray: SpanDate
359384 componentList : incident . componentList || [ ] ,
360385 group_id : incident . group_id ,
361386 nodata : groupedData [ i ] [ 2 ] === 'nodata' ? true : false ,
362- startDate : new Date ( startDate * 1000 ) ,
387+ startDate : new Date ( startDate ) ,
363388 fill :
364389 severity === 'Critical'
365390 ? barChartColorScheme . critical
366391 : severity === 'Warning'
367392 ? barChartColorScheme . warning
368393 : barChartColorScheme . info ,
369394 } ) ;
395+ if ( ! isNodata ) {
396+ prev = data [ i ] ;
397+ }
370398 }
371399
372400 return data ;
@@ -415,15 +443,26 @@ export const createAlertsChartBars = (alert: IncidentsDetailsAlert): AlertsChart
415443
416444 const data = [ ] ;
417445
418- for ( let i = 0 ; i < groupedData . length ; i ++ ) {
446+ let idx = alert . firstTimestamps . length - 1 ;
447+ for ( let i = groupedData . length - 1 ; i >= 0 ; i -- ) {
419448 const isLastElement = i === groupedData . length - 1 ;
420-
421- // to avoid certain edge cases the startDate should
422- // be the minimum between alert.firstTimestamp and groupedData[i][0]
423- // Round the result since groupedData comes from raw time series values
424- const startDate = roundTimestampToFiveMinutes (
425- Math . min ( alert . firstTimestamp , groupedData [ i ] [ 0 ] ) ,
426- ) ;
449+ const isNodata = groupedData [ i ] [ 2 ] === 'nodata' ;
450+
451+ let startDate = 0 ;
452+ if ( i === 0 ) {
453+ // For the first bar, use the minimum of alert's first timestamp and the first interval start
454+ // This handles the case when the alert was created within 5 minutes
455+ startDate = roundTimestampToFiveMinutes (
456+ Math . min ( parseInt ( alert . firstTimestamps [ idx ] [ 1 ] ) , groupedData [ i ] [ 0 ] ) ,
457+ ) ;
458+ idx -- ;
459+ } else {
460+ if ( ! isNodata && idx >= 0 ) {
461+ startDate = roundTimestampToFiveMinutes ( parseInt ( alert . firstTimestamps [ idx ] [ 1 ] ) ) ;
462+ idx -- ;
463+ }
464+ // Note: If isNodata, startDate remains 0 (not used in tooltips for nodata intervals)
465+ }
427466
428467 data . push ( {
429468 y0 : new Date ( groupedData [ i ] [ 0 ] * 1000 ) ,
0 commit comments