From 80c152c0eb83c90a2292651b615c8ab005c348bd Mon Sep 17 00:00:00 2001 From: Dominique Clarke Date: Tue, 12 Oct 2021 12:37:21 -0400 Subject: [PATCH] [Observability] [Exploratory View] add percentile ranks, show legend always, and fix field labels (#113765) * add percentile ranks, show legend always, and fix field labels * add 50th percentile * replace hard coded values with constant Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../configurations/constants/constants.ts | 16 ++++- .../configurations/lens_attributes.test.ts | 61 ++++++++++++++++++- .../configurations/lens_attributes.ts | 57 +++++++++++++++-- .../rum/kpi_over_time_config.ts | 2 + .../synthetics/kpi_over_time_config.ts | 12 +++- .../test_data/sample_attribute.ts | 1 + .../test_data/sample_attribute_cwv.ts | 1 + .../test_data/sample_attribute_kpi.ts | 1 + .../breakdown/breakdowns.test.tsx | 21 +++++++ .../series_editor/breakdown/breakdowns.tsx | 20 ++++-- .../expanded_series_row.test.tsx | 40 ++++++++++++ .../series_editor/expanded_series_row.tsx | 6 +- 12 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts index 68dcd77e98990..e4473b183d729 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/constants/constants.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { OperationType } from '../../../../../../../lens/public'; import { ReportViewType } from '../../types'; import { CLS_FIELD, @@ -13,6 +13,7 @@ import { LCP_FIELD, TBT_FIELD, TRANSACTION_TIME_TO_FIRST_BYTE, + TRANSACTION_DURATION, } from './elasticsearch_fieldnames'; import { AGENT_HOST_LABEL, @@ -45,6 +46,8 @@ import { TBT_LABEL, URL_LABEL, BACKEND_TIME_LABEL, + MONITORS_DURATION_LABEL, + PAGE_LOAD_TIME_LABEL, LABELS_FIELD, } from './labels'; @@ -69,9 +72,11 @@ export const FieldLabels: Record = { [FID_FIELD]: FID_LABEL, [CLS_FIELD]: CLS_LABEL, [TRANSACTION_TIME_TO_FIRST_BYTE]: BACKEND_TIME_LABEL, + [TRANSACTION_DURATION]: PAGE_LOAD_TIME_LABEL, 'monitor.id': MONITOR_ID_LABEL, 'monitor.status': MONITOR_STATUS_LABEL, + 'monitor.duration.us': MONITORS_DURATION_LABEL, 'agent.hostname': AGENT_HOST_LABEL, 'host.hostname': HOST_NAME_LABEL, @@ -86,6 +91,7 @@ export const FieldLabels: Record = { 'performance.metric': METRIC_LABEL, 'Business.KPI': KPI_LABEL, 'http.request.method': REQUEST_METHOD, + percentile: 'Percentile', LABEL_FIELDS_FILTER: LABELS_FIELD, LABEL_FIELDS_BREAKDOWN: 'Labels field', }; @@ -114,8 +120,16 @@ export const USE_BREAK_DOWN_COLUMN = 'USE_BREAK_DOWN_COLUMN'; export const FILTER_RECORDS = 'FILTER_RECORDS'; export const TERMS_COLUMN = 'TERMS_COLUMN'; export const OPERATION_COLUMN = 'operation'; +export const PERCENTILE = 'percentile'; export const REPORT_METRIC_FIELD = 'REPORT_METRIC_FIELD'; +export const PERCENTILE_RANKS = [ + '99th' as OperationType, + '95th' as OperationType, + '90th' as OperationType, + '75th' as OperationType, + '50th' as OperationType, +]; export const LABEL_FIELDS_FILTER = 'LABEL_FIELDS_FILTER'; export const LABEL_FIELDS_BREAKDOWN = 'LABEL_FIELDS_BREAKDOWN'; diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index 2781c26954234..139f9fe67c751 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -16,7 +16,7 @@ import { } from './constants/elasticsearch_fieldnames'; import { buildExistsFilter, buildPhrasesFilter } from './utils'; import { sampleAttributeKpi } from './test_data/sample_attribute_kpi'; -import { RECORDS_FIELD, REPORT_METRIC_FIELD, ReportTypes } from './constants'; +import { RECORDS_FIELD, REPORT_METRIC_FIELD, PERCENTILE_RANKS, ReportTypes } from './constants'; describe('Lens Attribute', () => { mockAppIndexPattern(); @@ -75,6 +75,63 @@ describe('Lens Attribute', () => { expect(lnsAttrKpi.getJSON()).toEqual(sampleAttributeKpi); }); + it('should return expected json for percentile breakdowns', function () { + const seriesConfigKpi = getDefaultConfigs({ + reportType: ReportTypes.KPI, + dataType: 'ux', + indexPattern: mockIndexPattern, + }); + + const lnsAttrKpi = new LensAttributes([ + { + filters: [], + seriesConfig: seriesConfigKpi, + time: { + from: 'now-1h', + to: 'now', + }, + indexPattern: mockIndexPattern, + name: 'ux-series-1', + breakdown: 'percentile', + reportDefinitions: {}, + selectedMetricField: 'transaction.duration.us', + color: '#54b399', + }, + ]); + + expect(lnsAttrKpi.getJSON().state.datasourceStates.indexpattern.layers.layer0.columns).toEqual({ + 'x-axis-column-layer0': { + dataType: 'date', + isBucketed: true, + label: '@timestamp', + operationType: 'date_histogram', + params: { + interval: 'auto', + }, + scale: 'interval', + sourceField: '@timestamp', + }, + ...PERCENTILE_RANKS.reduce((acc: Record, rank, index) => { + acc[`y-axis-column-${index === 0 ? 'layer' + index : index}`] = { + dataType: 'number', + filter: { + language: 'kuery', + query: 'transaction.type: page-load and processor.event: transaction', + }, + isBucketed: false, + label: `${rank} percentile of page load time`, + operationType: 'percentile', + params: { + percentile: Number(rank.slice(0, 2)), + }, + scale: 'ratio', + sourceField: 'transaction.duration.us', + }; + return acc; + }, {}), + }); + }); + it('should return main y axis', function () { expect(lnsAttr.getMainYAxis(layerConfig, 'layer0', '')).toEqual({ dataType: 'number', @@ -413,7 +470,7 @@ describe('Lens Attribute', () => { yConfig: [{ color: 'green', forAccessor: 'y-axis-column-layer0' }], }, ], - legend: { isVisible: true, position: 'right' }, + legend: { isVisible: true, showSingleSeries: true, position: 'right' }, preferredSeriesType: 'line', tickLabelsVisibilitySettings: { x: true, yLeft: true, yRight: true }, valueLabels: 'hide', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts index fa5a8beb0087d..e3dab3c4e91f0 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -37,6 +37,8 @@ import { REPORT_METRIC_FIELD, RECORDS_FIELD, RECORDS_PERCENTAGE_FIELD, + PERCENTILE, + PERCENTILE_RANKS, ReportTypes, } from './constants'; import { ColumnFilter, SeriesConfig, UrlFilter, URLReportDefinition } from '../types'; @@ -249,6 +251,30 @@ export class LensAttributes { }; } + getPercentileBreakdowns( + layerConfig: LayerConfig, + columnFilter?: string + ): Record { + const yAxisColumns = layerConfig.seriesConfig.yAxisColumns; + const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0]; + const lensColumns: Record = {}; + + // start at 1, because main y axis will have the first percentile breakdown + for (let i = 1; i < PERCENTILE_RANKS.length; i++) { + lensColumns[`y-axis-column-${i}`] = { + ...this.getColumnBasedOnType({ + sourceField: mainSourceField!, + operationType: PERCENTILE_RANKS[i], + label: mainLabel, + layerConfig, + colIndex: i, + }), + filter: { query: columnFilter || '', language: 'kuery' }, + }; + } + return lensColumns; + } + getPercentileNumberColumn( sourceField: string, percentileValue: string, @@ -258,7 +284,7 @@ export class LensAttributes { ...buildNumberColumn(sourceField), label: i18n.translate('xpack.observability.expView.columns.label', { defaultMessage: '{percentileValue} percentile of {sourceField}', - values: { sourceField: seriesConfig.labels[sourceField], percentileValue }, + values: { sourceField: seriesConfig.labels[sourceField]?.toLowerCase(), percentileValue }, }), operationType: 'percentile', params: { percentile: Number(percentileValue.split('th')[0]) }, @@ -328,6 +354,7 @@ export class LensAttributes { layerConfig: LayerConfig; colIndex?: number; }) { + const { breakdown, seriesConfig } = layerConfig; const { fieldMeta, columnType, fieldName, columnLabel, timeScale, columnFilters } = this.getFieldMeta(sourceField, layerConfig); @@ -348,6 +375,18 @@ export class LensAttributes { if (fieldType === 'date') { return this.getDateHistogramColumn(fieldName); } + + if (fieldType === 'number' && breakdown === PERCENTILE) { + return { + ...this.getPercentileNumberColumn( + fieldName, + operationType || PERCENTILE_RANKS[0], + seriesConfig! + ), + filter: colIndex !== undefined ? columnFilters?.[colIndex] : undefined, + }; + } + if (fieldType === 'number') { return this.getNumberColumn({ sourceField: fieldName, @@ -395,6 +434,7 @@ export class LensAttributes { } getMainYAxis(layerConfig: LayerConfig, layerId: string, columnFilter: string) { + const { breakdown } = layerConfig; const { sourceField, operationType, label } = layerConfig.seriesConfig.yAxisColumns[0]; if (sourceField === RECORDS_PERCENTAGE_FIELD) { @@ -407,7 +447,7 @@ export class LensAttributes { return this.getColumnBasedOnType({ sourceField, - operationType, + operationType: breakdown === PERCENTILE ? PERCENTILE_RANKS[0] : operationType, label, layerConfig, colIndex: 0, @@ -415,6 +455,7 @@ export class LensAttributes { } getChildYAxises(layerConfig: LayerConfig, layerId?: string, columnFilter?: string) { + const { breakdown } = layerConfig; const lensColumns: Record = {}; const yAxisColumns = layerConfig.seriesConfig.yAxisColumns; const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0]; @@ -424,7 +465,10 @@ export class LensAttributes { .supportingColumns; } - // 1 means there is only main y axis + if (yAxisColumns.length === 1 && breakdown === PERCENTILE) { + return this.getPercentileBreakdowns(layerConfig, columnFilter); + } + if (yAxisColumns.length === 1) { return lensColumns; } @@ -574,7 +618,7 @@ export class LensAttributes { layers[layerId] = { columnOrder: [ `x-axis-column-${layerId}`, - ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN + ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN && breakdown !== PERCENTILE ? [`breakdown-column-${layerId}`] : []), `y-axis-column-${layerId}`, @@ -588,7 +632,7 @@ export class LensAttributes { filter: { query: columnFilter, language: 'kuery' }, ...(timeShift ? { timeShift } : {}), }, - ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN + ...(breakdown && sourceField !== USE_BREAK_DOWN_COLUMN && breakdown !== PERCENTILE ? // do nothing since this will be used a x axis source { [`breakdown-column-${layerId}`]: this.getBreakdownColumn({ @@ -610,7 +654,7 @@ export class LensAttributes { getXyState(): XYState { return { - legend: { isVisible: true, position: 'right' }, + legend: { isVisible: true, showSingleSeries: true, position: 'right' }, valueLabels: 'hide', fittingFunction: 'Linear', curveType: 'CURVE_MONOTONE_X' as XYCurveType, @@ -636,6 +680,7 @@ export class LensAttributes { ], xAccessor: `x-axis-column-layer${index}`, ...(layerConfig.breakdown && + layerConfig.breakdown !== PERCENTILE && layerConfig.seriesConfig.xAxisColumn.sourceField !== USE_BREAK_DOWN_COLUMN ? { splitAccessor: `breakdown-column-layer${index}` } : {}), diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts index de4f6b2198dbd..000e50d7b3a52 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/rum/kpi_over_time_config.ts @@ -13,6 +13,7 @@ import { OPERATION_COLUMN, RECORDS_FIELD, REPORT_METRIC_FIELD, + PERCENTILE, ReportTypes, } from '../constants'; import { buildPhraseFilter } from '../utils'; @@ -81,6 +82,7 @@ export function getKPITrendsLensConfig({ indexPattern }: ConfigProps): SeriesCon USER_AGENT_OS, CLIENT_GEO_COUNTRY_NAME, USER_AGENT_DEVICE, + PERCENTILE, LABEL_FIELDS_BREAKDOWN, ], baseFilters: [ diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts index 65b43a83a8fb5..6df9cdcd0503a 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/synthetics/kpi_over_time_config.ts @@ -6,7 +6,13 @@ */ import { ConfigProps, SeriesConfig } from '../../types'; -import { FieldLabels, OPERATION_COLUMN, REPORT_METRIC_FIELD, ReportTypes } from '../constants'; +import { + FieldLabels, + OPERATION_COLUMN, + REPORT_METRIC_FIELD, + PERCENTILE, + ReportTypes, +} from '../constants'; import { CLS_LABEL, DCL_LABEL, @@ -44,7 +50,7 @@ export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): SeriesCon ], hasOperationType: false, filterFields: ['observer.geo.name', 'monitor.type', 'tags'], - breakdownFields: ['observer.geo.name', 'monitor.type', 'monitor.name'], + breakdownFields: ['observer.geo.name', 'monitor.type', 'monitor.name', PERCENTILE], baseFilters: [], palette: { type: 'palette', name: 'status' }, definitionFields: ['monitor.name', 'url.full'], @@ -98,6 +104,6 @@ export function getSyntheticsKPIConfig({ indexPattern }: ConfigProps): SeriesCon columnType: OPERATION_COLUMN, }, ], - labels: { ...FieldLabels }, + labels: { ...FieldLabels, [SUMMARY_UP]: UP_LABEL, [SUMMARY_DOWN]: DOWN_LABEL }, }; } diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts index 7e0ea1e575481..8254a5a816921 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute.ts @@ -187,6 +187,7 @@ export const sampleAttribute = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts index dff3d6b3ad5ef..adc6d4bb14462 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_cwv.ts @@ -134,6 +134,7 @@ export const sampleAttributeCoreWebVital = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts index 6ed9b4face6e3..8fbda9f6adc52 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/configurations/test_data/sample_attribute_kpi.ts @@ -89,6 +89,7 @@ export const sampleAttributeKpi = { ], legend: { isVisible: true, + showSingleSeries: true, position: 'right', }, preferredSeriesType: 'line', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx index cb683119384d9..8ed279ace28f6 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.test.tsx @@ -10,6 +10,7 @@ import { fireEvent, screen } from '@testing-library/react'; import { Breakdowns } from './breakdowns'; import { mockIndexPattern, mockUxSeries, render } from '../../rtl_helpers'; import { getDefaultConfigs } from '../../configurations/default_configs'; +import { RECORDS_FIELD } from '../../configurations/constants'; import { USER_AGENT_OS } from '../../configurations/constants/elasticsearch_fieldnames'; describe('Breakdowns', function () { @@ -56,6 +57,26 @@ describe('Breakdowns', function () { expect(setSeries).toHaveBeenCalledTimes(1); }); + it('does not show percentile breakdown for records metrics', function () { + const kpiConfig = getDefaultConfigs({ + reportType: 'kpi-over-time', + indexPattern: mockIndexPattern, + dataType: 'ux', + }); + + render( + + ); + + fireEvent.click(screen.getByTestId('seriesBreakdown')); + + expect(screen.queryByText('Percentile')).not.toBeInTheDocument(); + }); + it('should disable breakdowns when a different series has a breakdown', function () { const initSeries = { data: [mockUxSeries, { ...mockUxSeries, breakdown: undefined }], diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx index 7964abdeeddc5..a235cbd8852ad 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/breakdown/breakdowns.tsx @@ -10,7 +10,12 @@ import styled from 'styled-components'; import { EuiSuperSelect, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { useSeriesStorage } from '../../hooks/use_series_storage'; -import { LABEL_FIELDS_BREAKDOWN, USE_BREAK_DOWN_COLUMN } from '../../configurations/constants'; +import { + LABEL_FIELDS_BREAKDOWN, + USE_BREAK_DOWN_COLUMN, + RECORDS_FIELD, + PERCENTILE, +} from '../../configurations/constants'; import { SeriesConfig, SeriesUrl } from '../../types'; interface Props { @@ -51,6 +56,7 @@ export function Breakdowns({ seriesConfig, seriesId, series }: Props) { } const hasUseBreakdownColumn = seriesConfig.xAxisColumn.sourceField === USE_BREAK_DOWN_COLUMN; + const isRecordsMetric = series.selectedMetricField === RECORDS_FIELD; const items = seriesConfig.breakdownFields.map((breakdown) => ({ id: breakdown, @@ -64,11 +70,13 @@ export function Breakdowns({ seriesConfig, seriesId, series }: Props) { }); } - const options = items.map(({ id, label }) => ({ - inputDisplay: label, - value: id, - dropdownDisplay: label, - })); + const options = items + .map(({ id, label }) => ({ + inputDisplay: label, + value: id, + dropdownDisplay: label, + })) + .filter(({ value }) => !(value === PERCENTILE && isRecordsMetric)); let valueOfSelected = selectedBreakdown || (hasUseBreakdownColumn ? options[0].value : NO_BREAKDOWN); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx new file mode 100644 index 0000000000000..83958840f63d9 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.test.tsx @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { screen } from '@testing-library/react'; +import { ExpandedSeriesRow } from './expanded_series_row'; +import { mockIndexPattern, mockUxSeries, render } from '../rtl_helpers'; +import { getDefaultConfigs } from '../configurations/default_configs'; +import { PERCENTILE } from '../configurations/constants'; + +describe('ExpandedSeriesRow', function () { + const dataViewSeries = getDefaultConfigs({ + reportType: 'kpi-over-time', + indexPattern: mockIndexPattern, + dataType: 'ux', + }); + + it('should render properly', async function () { + render(); + + expect(screen.getByText('Breakdown by')).toBeInTheDocument(); + expect(screen.getByText('Operation')).toBeInTheDocument(); + }); + + it('should not display operation field when percentile breakdowns are applied', async function () { + render( + + ); + + expect(screen.queryByText('Operation')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx index ac71f4ff5abe0..180be1ac0414f 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/series_editor/expanded_series_row.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiHorizontalRule } from '@elastic/eui'; import { SeriesConfig, SeriesUrl } from '../types'; +import { PERCENTILE } from '../configurations/constants'; import { ReportDefinitionCol } from './columns/report_definition_col'; import { OperationTypeSelect } from './columns/operation_type_select'; import { parseCustomFieldName } from '../configurations/lens_attributes'; @@ -42,6 +43,9 @@ export function ExpandedSeriesRow(seriesProps: Props) { const columnType = getColumnType(seriesConfig, selectedMetricField); + // if the breakdown field is percentiles, we can't apply further operations + const hasPercentileBreakdown = series.breakdown === PERCENTILE; + return (
@@ -69,7 +73,7 @@ export function ExpandedSeriesRow(seriesProps: Props) { - {(hasOperationType || columnType === 'operation') && ( + {(hasOperationType || (columnType === 'operation' && !hasPercentileBreakdown)) && (