import React , { Fragment , FC , useContext , useEffect , useState , useReducer , useMemo } from 'react' ; import { EuiHorizontalRule } from '@elastic/eui' ; import { JobCreatorContext } from '../../../job_creator_context' ; import { PopulationJobCreator } from '../../../../../common/job_creator' ; import { LineChartData } from '../../../../../common/chart_loader' ; import { DropDownLabel , DropDownProps } from '../agg_select' ; import { newJobCapsService } from '../../../../../../../services/new_job_capabilities/new_job_capabilities_service' ; import { Field , AggFieldPair } from '../../../../../../../../../common/types/fields' ; import { sortFields } from '../../../../../../../../../common/util/fields_utils' ; import { getChartSettings , defaultChartSettings } from '../../../charts/common/settings' ; import { MetricSelector } from './metric_selector' ; import { PopulationFieldSelector } from '../population_field' ; import { ChartGrid } from './chart_grid' ; import { getToastNotificationService } from '../../../../../../../services/toast_notification_service' ; interface Props { setIsValid : ( na : boolean ) => void ; } type DetectorFieldValues = Record < number , string [ ] > ; export const PopulationDetectors = ( { setIsValid } ) => { const { jobCreator : jc , jobCreatorUpdate , jobCreatorUpdated , chartLoader , chartInterval , } = useContext ( JobCreatorContext ) ; const jobCreator = jc as PopulationJobCreator ; const fields = useMemo ( ( ) => sortFields ( [ ... newJobCapsService . fields , ... jobCreator . runtimeFields ] ) , [ ] ) ; const [ selectedOptions , setSelectedOptions ] = useState < DropDownProps > ( [ ] ) ; const [ aggFieldPairList , setAggFieldPairList ] = useState < AggFieldPair [ ] > ( jobCreator . aggFieldPairs ) ; const [ lineChartsData , setLineChartsData ] = useState < LineChartData > ( { } ) ; const [ loadingData , setLoadingData ] = useState ( false ) ; const [ start , setStart ] = useState ( jobCreator . start ) ; const [ end , setEnd ] = useState ( jobCreator . end ) ; const [ bucketSpanMs , setBucketSpanMs ] = useState ( jobCreator . bucketSpanMs ) ; const [ chartSettings , setChartSettings ] = useState ( defaultChartSettings ) ; const [ populationField , setPopulationField ] = useState ( jobCreator . populationField ) ; const [ fieldValuesPerDetector , setFieldValuesPerDetector ] = useState < DetectorFieldValues > ( { } ) ; const [ byFieldsUpdated , setByFieldsUpdated ] = useReducer < ( s : number , action : any ) => number > ( ( s ) => s + 1 , 0 ) ; const [ pageReady , setPageReady ] = useState ( false ) ; const updateByFields = ( ) => setByFieldsUpdated ( 0 ) ; function detectorChangeHandler ( selectedOptionsIn ) { addDetector ( selectedOptionsIn ) ; } function addDetector ( selectedOptionsIn ) { if ( selectedOptionsIn !== null && selectedOptionsIn . length ) { const option = selectedOptionsIn [ 0 ] as DropDownLabel ; if ( typeof option !== 'undefined' ) { const newPair = { agg : option . agg , field : option . field , by : { field : null , value : null } } ; setAggFieldPairList ( [ ... aggFieldPairList , newPair ] ) ; setSelectedOptions ( [ ] ) ; } else { setAggFieldPairList ( [ ] ) ; } } } function deleteDetector ( index ) { aggFieldPairList . splice ( index , 1 ) ; setAggFieldPairList ( [ ... aggFieldPairList ] ) ; updateByFields ( ) ; } useEffect ( ( ) => { setPageReady ( true ) ; } , [ ] ) ; useEffect ( ( ) => { jobCreator . removeAllDetectors ( ) ; aggFieldPairList . forEach ( ( pair , i ) => { jobCreator . addDetector ( pair . agg , pair . field ) ; if ( pair . by !== undefined ) { jobCreator . setByField ( pair . by . field , i ) ; } } ) ; jobCreatorUpdate ( ) ; loadCharts ( ) ; setIsValid ( aggFieldPairList . length > 0 ) ; } , [ aggFieldPairList . length ] ) ; useEffect ( ( ) => { loadCharts ( ) ; } , [ JSON . stringify ( fieldValuesPerDetector ) , populationField , pageReady ] ) ; useEffect ( ( ) => { if ( jobCreator . start !== start || jobCreator . end !== end ) { setStart ( jobCreator . start ) ; setEnd ( jobCreator . end ) ; loadCharts ( ) ; } if ( jobCreator . bucketSpanMs !== bucketSpanMs ) { setBucketSpanMs ( jobCreator . bucketSpanMs ) ; loadCharts ( ) ; } setPopulationField ( jobCreator . populationField ) ; let update = false ; const newList = [ ... aggFieldPairList ] ; newList . forEach ( ( pair , i ) => { const bf = jobCreator . getByField ( i ) ; if ( pair . by !== undefined && pair . by . field !== bf ) { pair . by . field = bf ; update = true ; } } ) ; if ( update ) { setAggFieldPairList ( newList ) ; updateByFields ( ) ; } } , [ jobCreatorUpdated ] ) ; useEffect ( ( ) => { loadFieldExamples ( ) ; } , [ populationField , byFieldsUpdated ] ) ; async function loadCharts ( ) { if ( allDataReady ( ) ) { setLoadingData ( true ) ; try { const cs = getChartSettings ( jobCreator , chartInterval ) ; setChartSettings ( cs ) ; const resp = await chartLoader . loadPopulationCharts ( jobCreator . start , jobCreator . end , aggFieldPairList , jobCreator . populationField , cs . intervalMs , jobCreator . runtimeMappings , jobCreator . datafeedConfig . indices_options ) ; setLineChartsData ( resp ) ; } catch ( error ) { getToastNotificationService ( ) . displayErrorToast ( error ) ; setLineChartsData ( [ ] ) ; } setLoadingData ( false ) ; } } async function loadFieldExamples ( ) { const promises = [ ] ; aggFieldPairList . forEach ( ( af , i ) => { if ( af . by !== undefined && af . by . field !== null ) { promises . push ( ( async ( index , field ) => { return { index , fields : await chartLoader . loadFieldExampleValues ( field , jobCreator . runtimeMappings , jobCreator . datafeedConfig . indices_options ) , } ; } ) ( i , af . by . field ) ) ; } } ) ; const results = await Promise . all ( promises ) ; const fieldValues = results . reduce ( ( p , c ) => { p [ c . index ] = c . fields ; return p ; } , { } ) as DetectorFieldValues ; const newPairs = aggFieldPairList . map ( ( pair , i ) => ( { ... pair , ... ( pair . by === undefined || pair . by . field === null ? { } : { by : { ... pair . by , value : fieldValues [ i ] [ 0 ] , } , } ) , } ) ) ; setAggFieldPairList ( [ ... newPairs ] ) ; setFieldValuesPerDetector ( fieldValues ) ; } function allDataReady ( ) { let ready = aggFieldPairList . length > 0 ; aggFieldPairList . forEach ( ( af ) => { if ( af . by !== undefined && af . by . field !== null ) { ready = ready && af . by . value !== null ; } } ) ; return ready ; } return ( < Fragment > < PopulationFieldSelector /> { populationField !== null && < EuiHorizontalRule margin = "l" / > } { populationField !== null && ( < ChartGrid aggFieldPairList = { aggFieldPairList } chartSettings = { chartSettings } splitField = { populationField } lineChartsData = { lineChartsData } modelData = { [ ] } anomalyData = { [ ] } deleteDetector = { deleteDetector } jobType = { jobCreator . type } fieldValuesPerDetector = { fieldValuesPerDetector } loading = { loadingData } / > ) } { populationField !== null && ( < MetricSelector fields = { fields } detectorChangeHandler = { detectorChangeHandler } selectedOptions = { selectedOptions } removeOptions = { [ ] } / > ) } < /Fragment>); } ;