import { useCallback , useEffect , useMemo } from 'react' ; import { SWIMLANE_TYPE } from '../explorer_constants' ; import { AppStateSelectedCells } from '../explorer_utils' ; import { ExplorerAppState } from '../../../../common/types/locator' ; import { useTimefilter } from '../../contexts/kibana' ; export const useSelectedCells = ( appState , setAppState , bucketIntervalInSeconds ) : [ AppStateSelectedCells | undefined , ( swimlaneSelectedCells : AppStateSelectedCells ) => void ] => { const timeFilter = useTimefilter ( ) ; const timeBounds = timeFilter . getBounds ( ) ; const selectedCells = useMemo ( ( ) => { if ( ! appState ?. mlExplorerSwimlane ?. selectedType ) { return ; } let times = appState . mlExplorerSwimlane . selectedTimes ?? appState . mlExplorerSwimlane . selectedTime ! ; if ( typeof times === 'number' ) { times = [ times , times + bucketIntervalInSeconds ! ] ; } let lanes = appState . mlExplorerSwimlane . selectedLanes ?? appState . mlExplorerSwimlane . selectedLane ! ; if ( typeof lanes === 'string' ) { lanes = [ lanes ] ; } return { type : appState . mlExplorerSwimlane . selectedType , lanes , times , showTopFieldValues : appState . mlExplorerSwimlane . showTopFieldValues , viewByFieldName : appState . mlExplorerSwimlane . viewByFieldName , } as AppStateSelectedCells ; } , [ JSON . stringify ( appState ?. mlExplorerSwimlane ) , bucketIntervalInSeconds ] ) ; const setSelectedCells = useCallback ( ( swimlaneSelectedCells ? ) => { const mlExplorerSwimlane = { ... appState . mlExplorerSwimlane , } as ExplorerAppState [ 'mlExplorerSwimlane' ] ; if ( swimlaneSelectedCells !== undefined ) { swimlaneSelectedCells . showTopFieldValues = false ; const currentSwimlaneType = selectedCells ?. type ; const currentShowTopFieldValues = selectedCells ?. showTopFieldValues ; const newSwimlaneType = swimlaneSelectedCells ?. type ; if ( ( currentSwimlaneType === SWIMLANE_TYPE . OVERALL && newSwimlaneType === SWIMLANE_TYPE . VIEW_BY ) || newSwimlaneType === SWIMLANE_TYPE . OVERALL || currentShowTopFieldValues === true ) { swimlaneSelectedCells . showTopFieldValues = true ; } mlExplorerSwimlane . selectedType = swimlaneSelectedCells . type ; mlExplorerSwimlane . selectedLanes = swimlaneSelectedCells . lanes ; mlExplorerSwimlane . selectedTimes = swimlaneSelectedCells . times ; mlExplorerSwimlane . showTopFieldValues = swimlaneSelectedCells . showTopFieldValues ; setAppState ( { mlExplorerSwimlane } ) ; } else { delete mlExplorerSwimlane . selectedType ; delete mlExplorerSwimlane . selectedLanes ; delete mlExplorerSwimlane . selectedTimes ; delete mlExplorerSwimlane . showTopFieldValues ; setAppState ( { mlExplorerSwimlane } ) ; } } , [ appState ?. mlExplorerSwimlane , selectedCells , setAppState ] ) ; /**
     * Adjust cell selection with respect to the time boundaries.
     * Reset it entirely when it out of range.
     */ useEffect ( function adjustSwimLaneTimeSelection ( ) { if ( selectedCells ?. times === undefined || bucketIntervalInSeconds === undefined ) return ; const [ selectedFrom , selectedTo ] = selectedCells . times ; /**
         * Because each cell on the swim lane represent the fixed bucket interval,
         * the selection range could be outside of the time boundaries with
         * correction within the bucket interval.
         */ const rangeFrom = timeBounds . min ! . unix ( ) - bucketIntervalInSeconds ; const rangeTo = timeBounds . max ! . unix ( ) + bucketIntervalInSeconds ; const resultFrom = Math . max ( selectedFrom , rangeFrom ) ; const resultTo = Math . min ( selectedTo , rangeTo ) ; const isSelectionOutOfRange = rangeFrom > resultTo || rangeTo < resultFrom ; if ( isSelectionOutOfRange ) { setSelectedCells ( ) ; return ; } if ( selectedFrom === resultFrom && selectedTo === resultTo ) { return ; } if ( resultFrom !== rangeFrom || resultTo !== rangeTo ) { setSelectedCells ( { ... selectedCells , times : [ resultFrom , resultTo ] , } ) ; } } , [ timeBounds . min ?. unix ( ) , timeBounds . max ?. unix ( ) , selectedCells , bucketIntervalInSeconds ] ) ; return [ selectedCells , setSelectedCells ] ; } ; export interface SelectionTimeRange { earliestMs : number ; latestMs : number ; } export function getTimeBoundsFromSelection ( selectedCells ) { if ( selectedCells ?. times === undefined ) { return ; } return { earliestMs : selectedCells . times [ 0 ] * 1000 , latestMs : selectedCells . times [ 1 ] * 1000 - 1 , } ; }