diff --git a/src/core_plugins/metrics/common/__tests__/calculate_label.js b/src/core_plugins/metrics/common/__tests__/calculate_label.js index 10414c15de61e..bb1ce3ebd38d0 100644 --- a/src/core_plugins/metrics/common/__tests__/calculate_label.js +++ b/src/core_plugins/metrics/common/__tests__/calculate_label.js @@ -38,6 +38,16 @@ describe('calculateLabel(metric, metrics)', () => { expect(label).to.equal('Derivative of Max of network.out.bytes'); }); + it('returns formated label for derivative of percentile', () => { + const metric = { id: 2, type: 'derivative', field: '1[50.0]' }; + const metrics = [ + { id: 1, type: 'percentile', field: 'network.out.bytes' }, + metric + ]; + const label = calculateLabel(metric, metrics); + expect(label).to.equal('Derivative of Percentile of network.out.bytes (50.0)'); + }); + it('returns formated label for pipeline aggs (deep)', () => { const metric = { id: 3, type: 'derivative', field: 2 }; const metrics = [ diff --git a/src/core_plugins/metrics/common/calculate_label.js b/src/core_plugins/metrics/common/calculate_label.js index 21d4d51191edf..c3f044bbfec27 100644 --- a/src/core_plugins/metrics/common/calculate_label.js +++ b/src/core_plugins/metrics/common/calculate_label.js @@ -1,4 +1,4 @@ -import _ from 'lodash'; +import { includes, startsWith } from 'lodash'; import lookup from './agg_lookup'; const paths = [ 'cumulative_sum', @@ -28,10 +28,22 @@ export default function calculateLabel(metric, metrics) { return `${lookup[metric.type]} (${metric.value}) of ${metric.field}`; } - if (_.includes(paths, metric.type)) { - const targetMetric = _.find(metrics, { id: metric.field }); + + if (includes(paths, metric.type)) { + let additionalLabel = ''; + const targetMetric = metrics.find(m => startsWith(metric.field, m.id)); const targetLabel = calculateLabel(targetMetric, metrics); - return `${lookup[metric.type]} of ${targetLabel}`; + // For percentiles we need to parse the field id to extract the percentile + // the user configured in the percentile aggregation and specified in the + // submetric they selected. This applies only to pipeline aggs. + if (targetMetric && targetMetric.type === 'percentile') { + const percentileValueMatch = /\[([0-9\.]+)\]$/; + const matches = metric.field.match(percentileValueMatch); + if (matches) { + additionalLabel += ` (${matches[1]})`; + } + } + return `${lookup[metric.type]} of ${targetLabel}${additionalLabel}`; } return `${lookup[metric.type]} of ${metric.field}`; diff --git a/src/core_plugins/metrics/public/components/aggs/metric_select.js b/src/core_plugins/metrics/public/components/aggs/metric_select.js index 8da3bbc9ad4b7..15c34e6fe6c3e 100644 --- a/src/core_plugins/metrics/public/components/aggs/metric_select.js +++ b/src/core_plugins/metrics/public/components/aggs/metric_select.js @@ -18,6 +18,14 @@ function createTypeFilter(restrict, exclude) { }; } + +// This filters out sibling aggs, percentiles, and special aggs (like Series Agg) +export function filterRows(row) { + return !/_bucket$/.test(row.type) + && !/^series/.test(row.type) + && !/^percentile/.test(row.type); +} + function MetricSelect(props) { const { restrict, @@ -30,8 +38,27 @@ function MetricSelect(props) { const metrics = props.metrics .filter(createTypeFilter(restrict, exclude)); - const options = calculateSiblings(metrics, metric) - .filter(row => !/_bucket$/.test(row.type) && !/^series/.test(row.type)) + const siblings = calculateSiblings(metrics, metric); + + // Percentiles need to be handled differently because one percentile aggregation + // could have multiple percentiles associated with it. So the user needs a way + // to specify which percentile the want to use. + const percentileOptions = siblings + .filter(row => /^percentile/.test(row.type)) + .reduce((acc, row) => { + const label = calculateLabel(row, metrics); + row.percentiles.forEach(p => { + if (p.value) { + const value = /\./.test(p.value) ? p.value : `${p.value}.0`; + acc.push({ value: `${row.id}[${value}]`, label: `${label} (${value})` }); + } + }); + return acc; + }, []); + + + const options = siblings + .filter(filterRows) .map(row => { const label = calculateLabel(row, metrics); return { value: row.id, label }; @@ -41,7 +68,7 @@ function MetricSelect(props) {