diff --git a/x-pack/plugins/apm/public/utils/formatters/__test__/formatters.test.ts b/x-pack/plugins/apm/common/utils/formatters.test.ts similarity index 96% rename from x-pack/plugins/apm/public/utils/formatters/__test__/formatters.test.ts rename to x-pack/plugins/apm/common/utils/formatters.test.ts index 66101baf3a746..ce317c5a6a827 100644 --- a/x-pack/plugins/apm/public/utils/formatters/__test__/formatters.test.ts +++ b/x-pack/plugins/apm/common/utils/formatters.test.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { asPercent } from '../formatters'; +import { asPercent } from './formatters'; describe('formatters', () => { describe('asPercent', () => { diff --git a/x-pack/plugins/apm/common/utils/formatters.ts b/x-pack/plugins/apm/common/utils/formatters.ts new file mode 100644 index 0000000000000..f7c609d949adf --- /dev/null +++ b/x-pack/plugins/apm/common/utils/formatters.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import numeral from '@elastic/numeral'; + +export function asPercent( + numerator: number, + denominator: number | undefined, + fallbackResult = '' +) { + if (!denominator || isNaN(numerator)) { + return fallbackResult; + } + + const decimal = numerator / denominator; + + // 33.2 => 33% + // 3.32 => 3.3% + // 0 => 0% + if (Math.abs(decimal) >= 0.1 || decimal === 0) { + return numeral(decimal).format('0%'); + } + + return numeral(decimal).format('0.0%'); +} diff --git a/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceStatsList.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceStatsList.tsx index be52018735099..ba4451c37b304 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceStatsList.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceStatsList.tsx @@ -8,8 +8,9 @@ import { i18n } from '@kbn/i18n'; import { isNumber } from 'lodash'; import React from 'react'; import styled from 'styled-components'; +import { asPercent } from '../../../../../common/utils/formatters'; import { ServiceNodeStats } from '../../../../../common/service_map'; -import { asDuration, asPercent, tpmUnit } from '../../../../utils/formatters'; +import { asDuration, tpmUnit } from '../../../../utils/formatters'; export const ItemRow = styled('tr')` line-height: 2; diff --git a/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx index 3cde48aa483cb..9940a7aabb219 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx @@ -13,6 +13,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; +import { asPercent } from '../../../../common/utils/formatters'; import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../common/i18n'; import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; import { Projection } from '../../../../common/projections'; @@ -20,11 +21,7 @@ import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { ManagedTable, ITableColumn } from '../../shared/ManagedTable'; import { useFetcher } from '../../../hooks/useFetcher'; -import { - asDynamicBytes, - asInteger, - asPercent, -} from '../../../utils/formatters'; +import { asDynamicBytes, asInteger } from '../../../utils/formatters'; import { ServiceNodeMetricOverviewLink } from '../../shared/Links/apm/ServiceNodeMetricOverviewLink'; import { truncate, px, unit } from '../../../style/variables'; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx index 1725a13f4da66..41c958838803e 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiToolTip } from '@elastic/eui'; -import { asPercent } from '../../../../utils/formatters'; +import { asPercent } from '../../../../../common/utils/formatters'; interface PercentOfParentProps { duration: number; diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx index 0dc2f607b1ef2..515fcbc88c901 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx @@ -5,32 +5,29 @@ */ import { + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, EuiPanel, EuiSpacer, EuiTitle, - EuiHorizontalRule, - EuiFlexGroup, - EuiFlexItem, } from '@elastic/eui'; import React, { useMemo } from 'react'; -import { EuiFlexGrid } from '@elastic/eui'; +import { useTrackPageview } from '../../../../../observability/public'; +import { Projection } from '../../../../common/projections'; +import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; +import { FETCH_STATUS } from '../../../hooks/useFetcher'; +import { useLocation } from '../../../hooks/useLocation'; import { useTransactionCharts } from '../../../hooks/useTransactionCharts'; import { useTransactionDistribution } from '../../../hooks/useTransactionDistribution'; +import { useUrlParams } from '../../../hooks/useUrlParams'; import { useWaterfall } from '../../../hooks/useWaterfall'; -import { TransactionCharts } from '../../shared/charts/TransactionCharts'; import { ApmHeader } from '../../shared/ApmHeader'; +import { TransactionCharts } from '../../shared/charts/TransactionCharts'; +import { HeightRetainer } from '../../shared/HeightRetainer'; +import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { TransactionDistribution } from './Distribution'; import { WaterfallWithSummmary } from './WaterfallWithSummmary'; -import { useLocation } from '../../../hooks/useLocation'; -import { useUrlParams } from '../../../hooks/useUrlParams'; -import { FETCH_STATUS } from '../../../hooks/useFetcher'; -import { TransactionBreakdown } from '../../shared/TransactionBreakdown'; -import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; -import { useTrackPageview } from '../../../../../observability/public'; -import { Projection } from '../../../../common/projections'; -import { LocalUIFilters } from '../../shared/LocalUIFilters'; -import { HeightRetainer } from '../../shared/HeightRetainer'; -import { ErroneousTransactionsRateChart } from '../../shared/charts/ErroneousTransactionsRateChart'; export function TransactionDetails() { const location = useLocation(); @@ -86,21 +83,9 @@ export function TransactionDetails() { - - - - - - - - - - - diff --git a/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx index 0757ae572152c..81d8a6f807375 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -7,7 +7,6 @@ import { EuiCallOut, EuiCode, - EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -29,13 +28,11 @@ import { useServiceTransactionTypes } from '../../../hooks/useServiceTransaction import { useTransactionCharts } from '../../../hooks/useTransactionCharts'; import { useTransactionList } from '../../../hooks/useTransactionList'; import { useUrlParams } from '../../../hooks/useUrlParams'; -import { ErroneousTransactionsRateChart } from '../../shared/charts/ErroneousTransactionsRateChart'; import { TransactionCharts } from '../../shared/charts/TransactionCharts'; import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink'; import { fromQuery, toQuery } from '../../shared/Links/url_helpers'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { TransactionTypeFilter } from '../../shared/LocalUIFilters/TransactionTypeFilter'; -import { TransactionBreakdown } from '../../shared/TransactionBreakdown'; import { TransactionList } from './List'; import { useRedirect } from './useRedirect'; @@ -125,20 +122,8 @@ export function TransactionOverview() { - - - - - - - - - - - diff --git a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx index 209657971620b..b908eb8da4d03 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx @@ -4,19 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useMemo } from 'react'; import { throttle } from 'lodash'; +import React, { useMemo } from 'react'; +import { asPercent } from '../../../../../common/utils/formatters'; +import { useUiTracker } from '../../../../../../observability/public'; import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; -import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; import { Maybe } from '../../../../../typings/common'; -import { TransactionLineChart } from '../../charts/TransactionCharts/TransactionLineChart'; -import { asPercent } from '../../../../utils/formatters'; -import { unit } from '../../../../style/variables'; +import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue'; -import { useUiTracker } from '../../../../../../observability/public'; +import { getEmptySeries } from '../../charts/CustomPlot/getEmptySeries'; +import { TransactionLineChart } from '../../charts/TransactionCharts/TransactionLineChart'; interface Props { timeseries: TimeSeries[]; + noHits: boolean; } const tickFormatY = (y: Maybe) => { @@ -29,8 +31,9 @@ const formatTooltipValue = (coordinate: Coordinate) => { : NOT_AVAILABLE_LABEL; }; -function TransactionBreakdownGraph(props: Props) { - const { timeseries } = props; +function TransactionBreakdownGraph({ timeseries, noHits }: Props) { + const { urlParams } = useUrlParams(); + const { rangeFrom, rangeTo } = urlParams; const trackApmEvent = useUiTracker({ app: 'apm' }); const handleHover = useMemo( () => @@ -38,15 +41,23 @@ function TransactionBreakdownGraph(props: Props) { [trackApmEvent] ); + const emptySeries = + rangeFrom && rangeTo + ? getEmptySeries( + new Date(rangeFrom).getTime(), + new Date(rangeTo).getTime() + ) + : []; + return ( ); } diff --git a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx deleted file mode 100644 index d3761cf0fe38e..0000000000000 --- a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import React from 'react'; -import { - EuiFlexGrid, - EuiFlexItem, - EuiFlexGroup, - EuiText, - EuiTitle, - EuiIcon, -} from '@elastic/eui'; -import styled from 'styled-components'; -import { asPercent } from '../../../utils/formatters'; - -interface TransactionBreakdownKpi { - name: string; - percentage: number; - color: string; -} - -interface Props { - kpis: TransactionBreakdownKpi[]; -} - -const Description = styled.span` - { - white-space: nowrap; - } -`; - -function KpiDescription({ name, color }: { name: string; color: string }) { - return ( - - - - - - - {name} - - - - ); -} - -function TransactionBreakdownKpiList({ kpis }: Props) { - return ( - - {kpis.map((kpi) => ( - - - - - - - - {asPercent(kpi.percentage, 1)} - - - - - ))} - - ); -} - -export { TransactionBreakdownKpiList }; diff --git a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx index 80ed9163ec08d..55826497ca385 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx @@ -3,28 +3,18 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiText, - EuiTitle, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { isEmpty } from 'lodash'; import React from 'react'; import { FETCH_STATUS } from '../../../hooks/useFetcher'; import { useTransactionBreakdown } from '../../../hooks/useTransactionBreakdown'; import { TransactionBreakdownGraph } from './TransactionBreakdownGraph'; -import { TransactionBreakdownKpiList } from './TransactionBreakdownKpiList'; - -const emptyMessage = i18n.translate('xpack.apm.transactionBreakdown.noData', { - defaultMessage: 'No data within this time range.', -}); function TransactionBreakdown() { const { data, status } = useTransactionBreakdown(); - const { kpis, timeseries } = data; - const noHits = data.kpis.length === 0 && status === FETCH_STATUS.SUCCESS; + const { timeseries } = data; + const noHits = isEmpty(timeseries) && status === FETCH_STATUS.SUCCESS; return ( @@ -39,14 +29,7 @@ function TransactionBreakdown() { - {noHits ? ( - {emptyMessage} - ) : ( - - )} - - - + diff --git a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js index 41925d651e361..501d30b5e2ba1 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js @@ -67,7 +67,7 @@ export class InnerCustomPlot extends PureComponent { (series) => { return series.slice( 0, - VISIBLE_LEGEND_COUNT + getHiddenLegendCount(series) + this.props.visibleLegendCount + getHiddenLegendCount(series) ); } ); @@ -128,14 +128,20 @@ export class InnerCustomPlot extends PureComponent { } render() { - const { series, truncateLegends, width, annotations } = this.props; + const { + series, + truncateLegends, + width, + annotations, + visibleLegendCount, + } = this.props; if (!width) { return null; } const hiddenSeriesCount = Math.max( - series.length - VISIBLE_LEGEND_COUNT - getHiddenLegendCount(series), + series.length - visibleLegendCount - getHiddenLegendCount(series), 0 ); const visibleSeries = this.getVisibleSeries({ series }); @@ -239,6 +245,7 @@ InnerCustomPlot.propTypes = { }) ), noHits: PropTypes.bool, + visibleLegendCount: PropTypes.number, onToggleLegend: PropTypes.func, }; @@ -249,6 +256,7 @@ InnerCustomPlot.defaultProps = { truncateLegends: false, xAxisTickSizeOuter: 0, noHits: false, + visibleLegendCount: VISIBLE_LEGEND_COUNT, }; export default makeWidthFlexible(InnerCustomPlot); diff --git a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx index 7721375a404c4..67b7fd31b05bc 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx @@ -19,7 +19,7 @@ const XY_HEIGHT = unit * 16; const XY_MARGIN = { top: unit, left: unit * 5, - right: 0, + right: unit, bottom: unit * 2, }; diff --git a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap index f413610ebd984..20636fa144479 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap @@ -82,7 +82,7 @@ Array [ className="rv-xy-plot__axis__line" style={Object {}} x1={0} - x2={720} + x2={704} y1={0} y2={0} /> @@ -93,7 +93,7 @@ Array [ @@ -434,7 +434,7 @@ Array [ > `; @@ -3018,7 +3018,7 @@ Array [ className="rv-xy-plot__axis__line" style={Object {}} x1={0} - x2={720} + x2={704} y1={0} y2={0} /> @@ -3029,7 +3029,7 @@ Array [ @@ -3370,7 +3370,7 @@ Array [ > @@ -5132,7 +5132,7 @@ Array [ rv-hint--verticalAlign-bottom" style={ Object { - "left": 440, + "left": 432, "position": "absolute", "top": 120, } @@ -5339,7 +5339,7 @@ Array [ > @@ -6097,7 +6097,7 @@ Array [ diff --git a/x-pack/plugins/apm/public/components/shared/charts/ErroneousTransactionsRateChart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/ErroneousTransactionsRateChart/index.tsx index 3b6d1684e08e1..1676d3f68b57c 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/ErroneousTransactionsRateChart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/ErroneousTransactionsRateChart/index.tsx @@ -8,11 +8,12 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import React, { useCallback } from 'react'; import { EuiPanel } from '@elastic/eui'; +import { EuiSpacer } from '@elastic/eui'; +import { asPercent } from '../../../../../common/utils/formatters'; import { useChartsSync } from '../../../../hooks/useChartsSync'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { callApmApi } from '../../../../services/rest/createCallApmApi'; -import { asPercent } from '../../../../utils/formatters'; // @ts-ignore import CustomPlot from '../CustomPlot'; @@ -71,6 +72,7 @@ export function ErroneousTransactionsRateChart() { })} + void; + visibleLegendCount?: number; onToggleLegend?: (disabledSeriesState: boolean[]) => void; } @@ -32,6 +33,7 @@ function TransactionLineChart(props: Props) { truncateLegends, stacked = false, onHover, + visibleLegendCount, onToggleLegend, } = props; @@ -59,6 +61,7 @@ function TransactionLineChart(props: Props) { height={height} truncateLegends={truncateLegends} {...(stacked ? { stackBy: 'y' } : {})} + visibleLegendCount={visibleLegendCount} onToggleLegend={onToggleLegend} /> ); diff --git a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx index d11925dc0303d..6ba080a07b9d3 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx @@ -13,7 +13,6 @@ import { EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Location } from 'history'; import React from 'react'; import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; import { @@ -29,6 +28,8 @@ import { asDecimal, tpmUnit } from '../../../../utils/formatters'; import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue'; import { BrowserLineChart } from './BrowserLineChart'; import { DurationByCountryMap } from './DurationByCountryMap'; +import { ErroneousTransactionsRateChart } from '../ErroneousTransactionsRateChart'; +import { TransactionBreakdown } from '../../TransactionBreakdown'; import { getResponseTimeTickFormatter, getResponseTimeTooltipFormatter, @@ -39,13 +40,11 @@ import { useFormatter } from './use_formatter'; interface TransactionChartProps { charts: ITransactionChartData; - location: Location; urlParams: IUrlParams; } export function TransactionCharts({ charts, - location, urlParams, }: TransactionChartProps) { const getTPMFormatter = (t: number) => { @@ -72,48 +71,56 @@ export function TransactionCharts({ - - - - - {responseTimeLabel(transactionType)} - - - - {(license) => ( - - )} - - - - + + + + {responseTimeLabel(transactionType)} + + + + {(license) => ( + + )} + + + - - - {tpmLabel(transactionType)} - - - + + {tpmLabel(transactionType)} + + + + + + + + + + + + + + {transactionType === TRANSACTION_PAGE_LOAD && ( <> diff --git a/x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts b/x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts index 2449c13f29435..9db78fde2d8c8 100644 --- a/x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts +++ b/x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts @@ -13,7 +13,7 @@ export function useTransactionBreakdown() { uiFilters, } = useUrlParams(); - const { data = { kpis: [], timeseries: [] }, error, status } = useFetcher( + const { data = { timeseries: [] }, error, status } = useFetcher( (callApmApi) => { if (serviceName && start && end && transactionType) { return callApmApi({ diff --git a/x-pack/plugins/apm/public/utils/formatters/formatters.ts b/x-pack/plugins/apm/public/utils/formatters/formatters.ts index 649f11063b149..6249ce53b6779 100644 --- a/x-pack/plugins/apm/public/utils/formatters/formatters.ts +++ b/x-pack/plugins/apm/public/utils/formatters/formatters.ts @@ -23,24 +23,3 @@ export function tpmUnit(type?: string) { defaultMessage: 'tpm', }); } - -export function asPercent( - numerator: number, - denominator: number | undefined, - fallbackResult = '' -) { - if (!denominator || isNaN(numerator)) { - return fallbackResult; - } - - const decimal = numerator / denominator; - - // 33.2 => 33% - // 3.32 => 3.3% - // 0 => 0% - if (Math.abs(decimal) >= 0.1 || decimal === 0) { - return numeral(decimal).format('0%'); - } - - return numeral(decimal).format('0.0%'); -} diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts index 731f75226cbe4..e943214b0b517 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.test.ts @@ -50,40 +50,9 @@ describe('getTransactionBreakdown', () => { setup: getMockSetup(noDataResponse), }); - expect(response.kpis.length).toBe(0); - expect(Object.keys(response.timeseries).length).toBe(0); }); - it('returns transaction breakdowns grouped by type and subtype', async () => { - const response = await getTransactionBreakdown({ - serviceName: 'myServiceName', - transactionType: 'request', - setup: getMockSetup(dataResponse), - }); - - expect(response.kpis.length).toBe(4); - - expect(response.kpis.map((kpi) => kpi.name)).toEqual([ - 'app', - 'dispatcher-servlet', - 'http', - 'postgresql', - ]); - - expect(response.kpis[0]).toEqual({ - name: 'app', - color: '#54b399', - percentage: 0.5408550899466306, - }); - - expect(response.kpis[3]).toEqual({ - name: 'postgresql', - color: '#9170b8', - percentage: 0.047366859295002, - }); - }); - it('returns a timeseries grouped by type and subtype', async () => { const response = await getTransactionBreakdown({ serviceName: 'myServiceName', @@ -98,7 +67,7 @@ describe('getTransactionBreakdown', () => { const appTimeseries = timeseries[0]; expect(appTimeseries.title).toBe('app'); expect(appTimeseries.type).toBe('areaStacked'); - expect(appTimeseries.hideLegend).toBe(true); + expect(appTimeseries.hideLegend).toBe(false); // empty buckets should result in null values for visible types expect(appTimeseries.data.length).toBe(276); diff --git a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts index fbdddea32deb4..9730ddbbf38d7 100644 --- a/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts +++ b/x-pack/plugins/apm/server/lib/transactions/breakdown/index.ts @@ -5,6 +5,7 @@ */ import { flatten, orderBy, last } from 'lodash'; +import { asPercent } from '../../../../common/utils/formatters'; import { ProcessorEvent } from '../../../../common/processor_event'; import { SERVICE_NAME, @@ -149,9 +150,16 @@ export async function getTransactionBreakdown({ ) : []; - const kpis = orderBy(visibleKpis, 'name').map((kpi, index) => { - return { + const kpis = orderBy( + visibleKpis.map((kpi) => ({ ...kpi, + lowerCaseName: kpi.name.toLowerCase(), + })), + 'lowerCaseName' + ).map((kpi, index) => { + const { lowerCaseName, ...rest } = kpi; + return { + ...rest, color: getVizColorForIndex(index), }; }); @@ -213,11 +221,9 @@ export async function getTransactionBreakdown({ color: kpi.color, type: 'areaStacked', data: timeseriesPerSubtype[kpi.name], - hideLegend: true, + hideLegend: false, + legendValue: asPercent(kpi.percentage, 1), })); - return { - kpis, - timeseries, - }; + return { timeseries }; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 83dac4912d4ac..911fb147511ab 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5067,7 +5067,6 @@ "xpack.apm.transactionActionMenu.viewInUptime": "ステータス", "xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "サンプルドキュメントを表示", "xpack.apm.transactionBreakdown.chartTitle": "スパンタイプ別時間", - "xpack.apm.transactionBreakdown.noData": "この時間範囲のデータがありません。", "xpack.apm.transactionCardinalityWarning.body": "一意のトランザクション名の数が構成された値{bucketSize}を超えています。エージェントを再構成し、類似したトランザクションをグループ化するか、{codeBlock}の値を増やしてください。", "xpack.apm.transactionCardinalityWarning.docsLink": "詳細はドキュメントをご覧ください", "xpack.apm.transactionCardinalityWarning.title": "このビューには、報告されたトランザクションのサブセットが表示されます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8b3a1941f450a..6495341539343 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5069,7 +5069,6 @@ "xpack.apm.transactionActionMenu.viewInUptime": "状态", "xpack.apm.transactionActionMenu.viewSampleDocumentLinkLabel": "查看样例文档", "xpack.apm.transactionBreakdown.chartTitle": "跨度类型花费的时间", - "xpack.apm.transactionBreakdown.noData": "此时间范围内没有数据。", "xpack.apm.transactionCardinalityWarning.body": "唯一事务名称的数目超过 {bucketSize} 的已配置值。尝试重新配置您的代理以对类似的事务分组或增大 {codeBlock} 的值", "xpack.apm.transactionCardinalityWarning.docsLink": "在文档中了解详情", "xpack.apm.transactionCardinalityWarning.title": "此视图显示已报告事务的子集。", diff --git a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/breakdown.ts b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/breakdown.ts index 5b61112a374c1..0b94abaa15890 100644 --- a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/breakdown.ts +++ b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/breakdown.ts @@ -6,7 +6,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; import expectedBreakdown from './expectation/breakdown.json'; -import expectedBreakdownWithTransactionName from './expectation/breakdown_transaction_name.json'; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); @@ -25,7 +24,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { `/api/apm/services/opbeans-node/transaction_groups/breakdown?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=${transactionType}` ); expect(response.status).to.be(200); - expect(response.body).to.eql({ kpis: [], timeseries: [] }); + expect(response.body).to.eql({ timeseries: [] }); }); }); @@ -47,15 +46,32 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); expect(response.status).to.be(200); - expect(response.body).to.eql(expectedBreakdownWithTransactionName); + const { timeseries } = response.body; + const { title, color, type, data, hideLegend, legendValue } = timeseries[0]; + expect(data).to.eql([ + { x: 1593413100000, y: null }, + { x: 1593413130000, y: null }, + { x: 1593413160000, y: null }, + { x: 1593413190000, y: null }, + { x: 1593413220000, y: null }, + { x: 1593413250000, y: null }, + { x: 1593413280000, y: null }, + { x: 1593413310000, y: 1 }, + { x: 1593413340000, y: null }, + ]); + expect(title).to.be('app'); + expect(color).to.be('#54b399'); + expect(type).to.be('areaStacked'); + expect(hideLegend).to.be(false); + expect(legendValue).to.be('100%'); }); - it('returns the top 4 by percentage and sorts them by name', async () => { + it('returns the transaction breakdown sorted by name', async () => { const response = await supertest.get( `/api/apm/services/opbeans-node/transaction_groups/breakdown?start=${start}&end=${end}&uiFilters=${uiFilters}&transactionType=${transactionType}` ); expect(response.status).to.be(200); - expect(response.body.kpis.map((kpi: { name: string }) => kpi.name)).to.eql([ + expect(response.body.timeseries.map((serie: { title: string }) => serie.title)).to.eql([ 'app', 'http', 'postgresql', diff --git a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown.json b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown.json index 3b884a9eb7907..8ffbba64ec7ab 100644 --- a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown.json +++ b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown.json @@ -1,26 +1,4 @@ { - "kpis":[ - { - "name":"app", - "percentage":0.16700861715223636, - "color":"#54b399" - }, - { - "name":"http", - "percentage":0.7702092736971686, - "color":"#6092c0" - }, - { - "name":"postgresql", - "percentage":0.0508822322527698, - "color":"#d36086" - }, - { - "name":"redis", - "percentage":0.011899876897825195, - "color":"#9170b8" - } - ], "timeseries":[ { "title":"app", @@ -64,7 +42,8 @@ "y":null } ], - "hideLegend":true + "hideLegend":false, + "legendValue": "17%" }, { "title":"http", @@ -108,7 +87,8 @@ "y":null } ], - "hideLegend":true + "hideLegend":false, + "legendValue": "77%" }, { "title":"postgresql", @@ -152,7 +132,8 @@ "y":null } ], - "hideLegend":true + "hideLegend":false, + "legendValue": "5.1%" }, { "title":"redis", @@ -196,7 +177,8 @@ "y":null } ], - "hideLegend":true + "hideLegend":false, + "legendValue": "1.2%" } ] } \ No newline at end of file diff --git a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown_transaction_name.json b/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown_transaction_name.json deleted file mode 100644 index b4f8e376d3609..0000000000000 --- a/x-pack/test/apm_api_integration/basic/tests/transaction_groups/expectation/breakdown_transaction_name.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "kpis":[ - { - "name":"app", - "percentage":1, - "color":"#54b399" - } - ], - "timeseries":[ - { - "title":"app", - "color":"#54b399", - "type":"areaStacked", - "data":[ - { - "x":1593413100000, - "y":null - }, - { - "x":1593413130000, - "y":null - }, - { - "x":1593413160000, - "y":null - }, - { - "x":1593413190000, - "y":null - }, - { - "x":1593413220000, - "y":null - }, - { - "x":1593413250000, - "y":null - }, - { - "x":1593413280000, - "y":null - }, - { - "x":1593413310000, - "y":1 - }, - { - "x":1593413340000, - "y":null - } - ], - "hideLegend":true - } - ] -} \ No newline at end of file