11/* eslint-disable react-hooks/exhaustive-deps */
22import { useMemo , useState , useEffect , useCallback } from 'react' ;
33import { useSafeFetch } from '../console/utils/safe-fetch-hook' ;
4- import { createAlertsQuery , fetchDataForIncidentsAndAlerts , fetchInstantData } from './api' ;
4+ import { createAlertsQuery , fetchDataForIncidentsAndAlerts } from './api' ;
55import { useTranslation } from 'react-i18next' ;
66import {
77 Bullseye ,
@@ -37,9 +37,8 @@ import {
3737 onDeleteIncidentFilterChip ,
3838 onIncidentFiltersSelect ,
3939 parseUrlParams ,
40- PROMETHEUS_QUERY_INTERVAL_SECONDS ,
41- roundTimestampToFiveMinutes ,
4240 updateBrowserUrl ,
41+ DAY_MS ,
4342} from './utils' ;
4443import { groupAlertsForTable , convertToAlerts } from './processAlerts' ;
4544import { CompressArrowsAltIcon , CompressIcon , FilterIcon } from '@patternfly/react-icons' ;
@@ -48,9 +47,7 @@ import {
4847 setAlertsAreLoading ,
4948 setAlertsData ,
5049 setAlertsTableData ,
51- setAlertsTimestamps ,
5250 setFilteredIncidentsData ,
53- setIncidentsTimestamps ,
5451 setIncidentPageFilterType ,
5552 setIncidents ,
5653 setIncidentsActiveFilters ,
@@ -150,10 +147,6 @@ const IncidentsPage = () => {
150147 ( state : MonitoringState ) => state . plugins . mcp . incidentsData . filteredIncidentsData ,
151148 ) ;
152149
153- const incidentsTimestamps = useSelector (
154- ( state : MonitoringState ) => state . plugins . mcp . incidentsData . incidentsTimestamps ,
155- ) ;
156-
157150 const selectedGroupId = incidentsActiveFilters . groupId ?. [ 0 ] ?? undefined ;
158151
159152 const incidentPageFilterTypeSelected = useSelector (
@@ -243,66 +236,27 @@ const IncidentsPage = () => {
243236 }
244237
245238 const currentTime = incidentsLastRefreshTime ;
246- const ONE_DAY = 24 * 60 * 60 * 1000 ;
247239
248- // Fetch timestamps and alerts in parallel, but wait for both before processing
249- const timestampPromise = fetchDataForIncidentsAndAlerts (
250- safeFetch ,
251- { endTime : currentTime , duration : 15 * ONE_DAY } ,
252- 'timestamp(ALERTS{alertstate="firing"})' ,
253- ) . then ( ( res ) => res . data . result ) ;
240+ // Always fetch 15 days of alert data so firstTimestamp is computed from full history
241+ const fetchTimeRanges = getIncidentsTimeRanges ( 15 * DAY_MS , currentTime ) ;
254242
255- const alertsPromise = Promise . all (
256- timeRanges . map ( async ( range ) => {
243+ Promise . all (
244+ fetchTimeRanges . map ( async ( range ) => {
257245 const response = await fetchDataForIncidentsAndAlerts (
258246 safeFetch ,
259247 range ,
260248 createAlertsQuery ( incidentForAlertProcessing ) ,
261249 ) ;
262250 return response . data . result ;
263251 } ) ,
264- ) ;
265-
266- Promise . all ( [ timestampPromise , alertsPromise ] )
267- . then ( ( [ timestampsResults , alertsResults ] ) => {
268- // Gaps detection here such that if the same timestamp has
269- // gaps greater than 5 minutes, this will be added more than one time.
270- // For example, if there is a metric for AlertH_Gapped
271- // with values:[ "1770699000", "1770699300", "1770708300", "1770708600", "1770708900"]
272- // there will be two gaps detected. With the following min values: 1770699300 and 1770699300
273- // the interval will be [1770699300 - 1770699300] and [1770708300 - 1770699300]
274-
275- const timestampsValues = timestampsResults ?. map ( ( result : any ) => ( {
276- ...result ,
277- value : detectMinForEachGap ( result . values , PROMETHEUS_QUERY_INTERVAL_SECONDS ) ,
278- } ) ) ;
279-
280- // Round timestamp values before storing
281- const roundedTimestamps =
282- timestampsValues ?. map ( ( result : any ) => ( {
283- ...result ,
284- value : result . value . map ( ( value : any ) => [
285- value [ 0 ] ,
286- roundTimestampToFiveMinutes ( parseInt ( value [ 1 ] ) ) . toString ( ) ,
287- ] ) ,
288- } ) ) || [ ] ;
289-
290- const fetchedAlertsTimestamps = {
291- minOverTime : roundedTimestamps ,
292- lastOverTime : [ ] ,
293- } ;
294- dispatch (
295- setAlertsTimestamps ( {
296- alertsTimestamps : fetchedAlertsTimestamps ,
297- } ) ,
298- ) ;
299-
252+ )
253+ . then ( ( alertsResults ) => {
300254 const prometheusResults = alertsResults . flat ( ) ;
301255 const alerts = convertToAlerts (
302256 prometheusResults ,
303257 incidentForAlertProcessing ,
304258 currentTime ,
305- fetchedAlertsTimestamps ,
259+ daysSpan ,
306260 ) ;
307261 dispatch (
308262 setAlertsData ( {
@@ -342,68 +296,41 @@ const IncidentsPage = () => {
342296 ? incidentsActiveFilters . days [ 0 ] . split ( ' ' ) [ 0 ] + 'd'
343297 : '' ,
344298 ) ;
345- const calculatedTimeRanges = getIncidentsTimeRanges ( daysDuration , currentTime ) ;
346299
347300 const isGroupSelected = ! ! selectedGroupId ;
348301 const incidentsQuery = isGroupSelected
349302 ? `cluster_health_components_map{group_id='${ selectedGroupId } '}`
350303 : 'cluster_health_components_map' ;
351304
352- // Fetch timestamps and incidents in parallel, but wait for both before processing
353- const timestampPromise = fetchInstantData (
354- safeFetch ,
355- 'min_over_time(timestamp(cluster_health_components_map)[15d:5m])' ,
356- ) . then ( ( res ) => res . data . result ) ;
305+ // Always fetch 15 days of data so firstTimestamp is computed from full history
306+ const fetchTimeRanges = getIncidentsTimeRanges ( 15 * DAY_MS , currentTime ) ;
357307
358- const incidentsPromise = Promise . all (
359- calculatedTimeRanges . map ( async ( range ) => {
308+ Promise . all (
309+ fetchTimeRanges . map ( async ( range ) => {
360310 const response = await fetchDataForIncidentsAndAlerts ( safeFetch , range , incidentsQuery ) ;
361311 return response . data . result ;
362312 } ) ,
363- ) ;
364-
365- Promise . all ( [ timestampPromise , incidentsPromise ] )
366- . then ( ( [ timestampsResults , incidentsResults ] ) => {
367- // Round timestamp values before storing
368- const roundedTimestamps =
369- timestampsResults ?. map ( ( result : any ) => ( {
370- ...result ,
371- value : [
372- result . value [ 0 ] ,
373- roundTimestampToFiveMinutes ( parseInt ( result . value [ 1 ] ) ) . toString ( ) ,
374- ] ,
375- } ) ) || [ ] ;
376-
377- const fetchedTimestamps = {
378- minOverTime : roundedTimestamps ,
379- lastOverTime : [ ] ,
380- } ;
381- dispatch (
382- setIncidentsTimestamps ( {
383- incidentsTimestamps : fetchedTimestamps ,
384- } ) ,
385- ) ;
386-
313+ )
314+ . then ( ( incidentsResults ) => {
387315 const prometheusResults = incidentsResults . flat ( ) ;
388- const incidents = convertToIncidents ( prometheusResults , currentTime ) ;
316+ const incidents = convertToIncidents ( prometheusResults , currentTime , daysDuration ) ;
389317
390318 // Update the raw, unfiltered incidents state
391319 dispatch ( setIncidents ( { incidents } ) ) ;
392320
321+ const filteredData = filterIncident ( incidentsActiveFilters , incidents ) ;
322+
393323 // Filter the incidents and dispatch
394324 dispatch (
395325 setFilteredIncidentsData ( {
396- filteredIncidentsData : filterIncident ( incidentsActiveFilters , incidents ) ,
326+ filteredIncidentsData : filteredData ,
397327 } ) ,
398328 ) ;
399329
400330 setIncidentsAreLoading ( false ) ;
401331
402332 if ( isGroupSelected ) {
403- // Use fetchedTimestamps directly instead of stale closure value
404- setIncidentForAlertProcessing (
405- processIncidentsForAlerts ( prometheusResults , fetchedTimestamps ) ,
406- ) ;
333+ setIncidentForAlertProcessing ( processIncidentsForAlerts ( prometheusResults ) ) ;
407334 dispatch ( setAlertsAreLoading ( { alertsAreLoading : true } ) ) ;
408335 } else {
409336 closeDropDownFilters ( ) ;
@@ -724,7 +651,6 @@ const IncidentsPage = () => {
724651 < StackItem >
725652 < IncidentsChart
726653 incidentsData = { filteredData }
727- incidentsTimestamps = { incidentsTimestamps }
728654 chartDays = { timeRanges . length }
729655 theme = { theme }
730656 selectedGroupId = { selectedGroupId }
@@ -759,30 +685,3 @@ export const McpCmoAlertingPage = () => {
759685 </ MonitoringProvider >
760686 ) ;
761687} ;
762-
763- /**
764- * @param {Array<Array> } dataValues - The matrix from out.json (data.result[0].values)
765- * @param {number } gapThreshold - e.g., 300
766- */
767- const detectMinForEachGap = ( dataValues , gapThreshold ) => {
768- if ( ! dataValues || dataValues . length === 0 ) return [ ] ;
769-
770- const mins = [ ] ;
771- let currentMin = dataValues [ 0 ] ;
772-
773- // Start from the second element to compare with the previous one
774- for ( let i = 1 ; i < dataValues . length ; i ++ ) {
775- const delta = dataValues [ i ] [ 1 ] - dataValues [ i - 1 ] [ 1 ] ;
776-
777- if ( delta > gapThreshold ) {
778- // Gap detected: save the min of the interval that just ended
779- mins . push ( currentMin ) ;
780- // The current timestamp is the min of the NEW interval
781- currentMin = dataValues [ i ] ;
782- }
783- }
784-
785- // Always push the min of the last interval
786- mins . push ( currentMin ) ;
787- return mins ;
788- } ;
0 commit comments