import { EuiFlexItem , EuiPanel } from '@elastic/eui' ; import { orderBy } from 'lodash' ; import React , { useState } from 'react' ; import uuid from 'uuid' ; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context' ; import { useLegacyUrlParams } from '../../../context/url_params_context/use_url_params' ; import { useApmParams } from '../../../hooks/use_apm_params' ; import { FETCH_STATUS , useFetcher } from '../../../hooks/use_fetcher' ; import { useTimeRange } from '../../../hooks/use_time_range' ; import { APIReturnType } from '../../../services/rest/createCallApmApi' ; import { InstancesLatencyDistributionChart } from '../../shared/charts/instances_latency_distribution_chart' ; import { getTimeRangeComparison } from '../../shared/time_comparison/get_time_range_comparison' ; import { ServiceOverviewInstancesTable , TableOptions , } from './service_overview_instances_table' ; interface ServiceOverviewInstancesChartAndTableProps { chartHeight : number ; serviceName : string ; } type ApiResponseMainStats = APIReturnType < 'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics' > ; type ApiResponseDetailedStats = APIReturnType < 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics' > ; const INITIAL_STATE_MAIN_STATS = { currentPeriodItems : [ ] as ApiResponseMainStats [ 'currentPeriod' ] , previousPeriodItems : [ ] as ApiResponseMainStats [ 'previousPeriod' ] , requestId : undefined , currentPeriodItemsCount : 0 , } ; const INITIAL_STATE_DETAILED_STATISTICS = { currentPeriod : { } , previousPeriod : { } , } ; export type SortField = 'serviceNodeName' | 'latency' | 'throughput' | 'errorRate' | 'cpuUsage' | 'memoryUsage' ; export type SortDirection = 'asc' | 'desc' ; export const PAGE_SIZE = 5 ; const DEFAULT_SORT = { direction : 'desc' as const , field : 'throughput' as const , } ; export function ServiceOverviewInstancesChartAndTable ( { chartHeight , serviceName , } ) { const { transactionType } = useApmServiceContext ( ) ; const [ tableOptions , setTableOptions ] = useState < TableOptions > ( { pageIndex : 0 , sort : DEFAULT_SORT , } ) ; const { pageIndex , sort } = tableOptions ; const { direction , field } = sort ; const { query : { environment , kuery , rangeFrom , rangeTo } , } = useApmParams ( '/services/{serviceName}/overview' ) ; const { urlParams : { latencyAggregationType , comparisonType , comparisonEnabled } , } = useLegacyUrlParams ( ) ; const { start , end } = useTimeRange ( { rangeFrom , rangeTo } ) ; const { comparisonStart , comparisonEnd } = getTimeRangeComparison ( { start , end , comparisonType , comparisonEnabled , } ) ; const { data : mainStatsData = INITIAL_STATE_MAIN_STATS , status : mainStatsStatus , } = useFetcher ( ( callApmApi ) => { if ( ! start || ! end || ! transactionType || ! latencyAggregationType ) { return ; } return callApmApi ( { endpoint : 'GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics' , params : { path : { serviceName , } , query : { environment , kuery , latencyAggregationType , start , end , transactionType , comparisonStart , comparisonEnd , } , } , } ) . then ( ( response ) => { return { requestId : uuid ( ) , currentPeriodItems : response . currentPeriod , currentPeriodItemsCount : response . currentPeriod . length , previousPeriodItems : response . previousPeriod , } ; } ) ; } , [ environment , kuery , latencyAggregationType , start , end , serviceName , transactionType , pageIndex , field , direction , comparisonType , comparisonEnabled , ] ) ; const { currentPeriodItems , previousPeriodItems , requestId , currentPeriodItemsCount , } = mainStatsData ; const currentPeriodOrderedItems = orderBy ( currentPeriodItems . map ( ( item ) => ( { ... item , latency : item . latency ?? 0 , throughput : item . throughput ?? 0 , errorRate : item . errorRate ?? 0 , cpuUsage : item . cpuUsage ?? 0 , memoryUsage : item . memoryUsage ?? 0 , } ) ) , field , direction ) . slice ( pageIndex * PAGE_SIZE , ( pageIndex + 1 ) * PAGE_SIZE ) ; const { data : detailedStatsData = INITIAL_STATE_DETAILED_STATISTICS } = useFetcher ( ( callApmApi ) => { if ( ! start || ! end || ! transactionType || ! latencyAggregationType || ! currentPeriodItemsCount ) { return ; } return callApmApi ( { endpoint : 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics' , params : { path : { serviceName , } , query : { environment , kuery , latencyAggregationType , start , end , numBuckets : 20 , transactionType , serviceNodeIds : JSON . stringify ( currentPeriodOrderedItems . map ( ( item ) => item . serviceNodeName ) ) , comparisonStart , comparisonEnd , } , } , } ) ; } , [ requestId ] , { preservePreviousData : false } ) ; return ( < > < EuiFlexItem grow = { 3 } > < InstancesLatencyDistributionChart height = { chartHeight } items = { currentPeriodItems } status = { mainStatsStatus } comparisonItems = { previousPeriodItems } / > < /EuiFlexItem> < EuiFlexItem grow = { 7 } > < EuiPanel hasBorder = { true } > < ServiceOverviewInstancesTable mainStatsItems = { currentPeriodOrderedItems } mainStatsStatus = { mainStatsStatus } mainStatsItemCount = { currentPeriodItemsCount } detailedStatsData = { detailedStatsData } serviceName = { serviceName } tableOptions = { tableOptions } isLoading = { mainStatsStatus === FETCH_STATUS . LOADING } isNotInitiated = { mainStatsStatus === FETCH_STATUS . NOT_INITIATED } onChangeTableOptions = { ( newTableOptions ) => { setTableOptions ( { pageIndex : newTableOptions . page ?. index ?? 0 , sort : newTableOptions . sort ? { field : newTableOptions . sort . field as SortField , direction : newTableOptions . sort . direction , } : DEFAULT_SORT , } ) ; } } /> < /EuiPanel> < /EuiFlexItem> < />); }