From 3e39342b3e675b087a176e7230d2e32aba2399e2 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Mon, 12 Sep 2022 17:11:10 +0300 Subject: [PATCH] Fixed pipeline and terms aggs. Added timeShift arg. --- .../configurations/xy/configuration.test.ts | 2 + .../lib/configurations/xy/configuration.ts | 2 + .../convert_to_lens/lib/convert/column.ts | 9 +- .../lib/convert/cumulative_sum.ts | 5 +- .../lib/convert/filter_ratio.ts | 5 +- .../convert_to_lens/lib/convert/formula.ts | 46 ++++--- .../convert_to_lens/lib/convert/index.ts | 2 +- .../lib/convert/parent_pipeline.test.ts | 12 +- .../lib/convert/parent_pipeline.ts | 19 +-- .../lib/convert/std_deviation.ts | 5 +- .../convert_to_lens/lib/convert/terms.test.ts | 8 +- .../convert_to_lens/lib/convert/terms.ts | 7 +- .../lib/metrics/counter_rate_formula.test.ts | 3 +- .../lib/metrics/counter_rate_formula.ts | 15 ++- .../lib/metrics/filter_ratio_formula.test.ts | 16 ++- .../lib/metrics/filter_ratio_formula.ts | 32 ++--- .../convert_to_lens/lib/metrics/index.ts | 3 +- .../lib/metrics/metrics_helpers.test.ts | 2 +- .../lib/metrics/metrics_helpers.ts | 102 +++++++++------- .../lib/metrics/parent_pipeline_formula.ts | 68 ----------- ...rmula.test.ts => pipeline_formula.test.ts} | 60 +++++---- .../lib/metrics/pipeline_formula.ts | 58 +++++++++ .../metrics/sibling_pipeline_formula.test.ts | 114 ------------------ .../lib/metrics/sibling_pipeline_formula.ts | 71 ----------- .../lib/series/buckets_columns.ts | 4 +- .../convert_to_lens/timeseries/index.ts | 6 + .../public/convert_to_lens/top_n/index.ts | 6 + .../public/convert_to_lens/types.ts | 5 + .../common/convert_to_lens/types/common.ts | 2 +- .../indexpattern_suggestions.ts | 37 ++++-- .../operations/definitions/terms/index.tsx | 1 + .../operations/layer_helpers.ts | 6 +- 32 files changed, 322 insertions(+), 411 deletions(-) delete mode 100644 src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.ts rename src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/{parent_pipeline_formula.test.ts => pipeline_formula.test.ts} (74%) create mode 100644 src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts delete mode 100644 src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.test.ts delete mode 100644 src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.ts diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.test.ts index ae3f75bf5905d..485dc6a84fc3e 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.test.ts @@ -28,6 +28,8 @@ describe('getConfigurationForTimeseries', () => { }, yLeftExtent: { mode: 'full' }, yRightExtent: { mode: 'full' }, + yLeftScale: 'linear', + yRightScale: 'linear', }); }); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.ts index b28e3767135c4..3108d373fe747 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/configuration.ts @@ -33,6 +33,8 @@ export const getConfigurationForTimeseries = ( }, yLeftExtent: extents.yLeftExtent, yRightExtent: extents.yRightExtent, + yLeftScale: model.axis_scale === 'log' ? 'log' : 'linear', + yRightScale: model.axis_scale === 'log' ? 'log' : 'linear', }; }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts index 1c1ed33958971..f836b28f5c605 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/column.ts @@ -34,7 +34,7 @@ const isSupportedFormat = (format: string) => ['bytes', 'number', 'percent'].inc export const getFormat = (series: Series): FormatParams => { let suffix; - if (!series.formatter) { + if (!series.formatter || series.formatter === 'default') { return {}; } @@ -44,10 +44,12 @@ export const getFormat = (series: Series): FormatParams => { // not supported formatters should be converted to number if (!isSupportedFormat(series.formatter)) { - return { format: { id: DATA_FORMATTERS.NUMBER, ...(suffix && { params: { suffix } }) } }; + return { + format: { id: DATA_FORMATTERS.NUMBER, ...(suffix && { params: { suffix, decimals: 2 } }) }, + }; } - return { format: { id: series.formatter, ...(suffix && { params: { suffix } }) } }; + return { format: { id: series.formatter, ...(suffix && { params: { suffix, decimals: 2 } }) } }; }; export const createColumn = ( @@ -63,6 +65,7 @@ export const createColumn = ( isSplit, reducedTimeRange, filter: series.filter, + timeShift: series.offset_time, timeScale: getTimeScale(metric), meta: { metricId: metric.id }, }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts index 8da6730b17c1c..8733b100f9a95 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/cumulative_sum.ts @@ -7,7 +7,7 @@ */ import { METRIC_TYPES } from '@kbn/data-plugin/public'; -import { SUPPORTED_METRICS, getParentPipelineSeriesFormula } from '../metrics'; +import { SUPPORTED_METRICS, getPipelineSeriesFormula } from '../metrics'; import { createFormulaColumn } from './formula'; import { computeParentPipelineColumns } from './parent_pipeline'; import { CommonColumnsConverterArgs } from './types'; @@ -33,9 +33,10 @@ export const convertToCumulativeSumColumns = ( // and everything else as formula if (pipelineAgg.name !== 'count' && pipelineAgg.name !== 'sum') { const metaValue = Number(meta?.replace(']', '')); - formula = getParentPipelineSeriesFormula(metrics, subFunctionMetric, pipelineAgg, metric.type, { + formula = getPipelineSeriesFormula(metric, metrics, subFunctionMetric, { metaValue, reducedTimeRange, + timeShift: series.offset_time, }); if (!formula) { return null; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filter_ratio.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filter_ratio.ts index 0b4f591d92503..9ed19035697fe 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filter_ratio.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/filter_ratio.ts @@ -15,7 +15,10 @@ export const convertFilterRatioToFormulaColumn = ( reducedTimeRange?: string ): FormulaColumn | null => { const metric = metrics[metrics.length - 1]; - const formula = getFilterRatioFormula(metric, reducedTimeRange); + const formula = getFilterRatioFormula(metric, { + reducedTimeRange, + timeShift: series.offset_time, + }); if (!formula) { return null; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts index 44d659e18fed3..d3f1f6e2640e6 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/formula.ts @@ -11,8 +11,9 @@ import { FormulaParams } from '@kbn/visualizations-plugin/common/convert_to_lens import { CommonColumnConverterArgs, CommonColumnsConverterArgs, FormulaColumn } from './types'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import type { Metric } from '../../../../common/types'; -import { getFormulaEquivalent, getSiblingPipelineSeriesFormula } from '../metrics'; +import { getFormulaEquivalent, getPipelineSeriesFormula } from '../metrics'; import { createColumn, getFormat } from './column'; +import { AdditionalFormulaArgs } from '../../types'; type OtherFormulaAggregations = | typeof TSVB_METRIC_TYPES.POSITIVE_ONLY @@ -43,7 +44,7 @@ const convertFormulaScriptForPercentileAggs = ( variables: Exclude, metric: Metric, allAggMetrics: Metric[], - reducedTimeRange?: string + additionalArgs: AdditionalFormulaArgs ) => { variables.forEach((variable) => { const [_, meta] = variable?.field?.split('[') ?? []; @@ -51,7 +52,7 @@ const convertFormulaScriptForPercentileAggs = ( if (!metaValue) { return; } - const script = getFormulaEquivalent(metric, allAggMetrics, { metaValue, reducedTimeRange }); + const script = getFormulaEquivalent(metric, allAggMetrics, { metaValue, ...additionalArgs }); if (!script) { return; } @@ -65,9 +66,9 @@ const convertFormulaScriptForAggs = ( variables: Exclude, metric: Metric, allAggMetrics: Metric[], - reducedTimeRange?: string + additionalArgs: AdditionalFormulaArgs ) => { - const script = getFormulaEquivalent(metric, allAggMetrics, { reducedTimeRange }); + const script = getFormulaEquivalent(metric, allAggMetrics, { ...additionalArgs }); if (!script) { return null; } @@ -107,21 +108,15 @@ export const convertMathToFormulaColumn = ( // should treat percentiles differently if (notMathMetric.type === 'percentile' || notMathMetric.type === 'percentile_rank') { - script = convertFormulaScriptForPercentileAggs( - script!, - variables, - notMathMetric, - metrics, - reducedTimeRange - ); + script = convertFormulaScriptForPercentileAggs(script!, variables, notMathMetric, metrics, { + reducedTimeRange, + timeShift: series.offset_time, + }); } else { - script = convertFormulaScriptForAggs( - script!, - variables, - notMathMetric, - metrics, - reducedTimeRange - ); + script = convertFormulaScriptForAggs(script!, variables, notMathMetric, metrics, { + reducedTimeRange, + timeShift: series.offset_time, + }); } } @@ -143,8 +138,19 @@ export const convertOtherAggsToFormulaColumn = ( reducedTimeRange?: string ): FormulaColumn | null => { const metric = metrics[metrics.length - 1]; + const [fieldId, meta] = metric?.field?.split('[') ?? []; + const subFunctionMetric = metrics.find(({ id }) => id === fieldId); + const metaValue = meta ? Number(meta?.replace(']', '')) : undefined; + + if (!subFunctionMetric) { + return null; + } - const formula = getSiblingPipelineSeriesFormula(aggregation, metric, metrics, reducedTimeRange); + const formula = getPipelineSeriesFormula(metric, metrics, subFunctionMetric, { + metaValue, + reducedTimeRange, + timeShift: series.offset_time, + }); if (!formula) { return null; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts index 4d6135ee3d5b2..84c7b32e10763 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/index.ts @@ -20,7 +20,7 @@ export { convertToLastValueColumn } from './last_value'; export { convertToStaticValueColumn } from './static_value'; export { convertToFiltersColumn } from './filters'; export { convertToDateHistogramColumn } from './date_histogram'; -export { converToTermsColumn } from './terms'; +export { convertToTermsColumn } from './terms'; export { convertToCounterRateColumn } from './counter_rate'; export { convertToStandartDeviationColumn } from './std_deviation'; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.test.ts index 95f83d48d8258..6defaba409741 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.test.ts @@ -467,8 +467,8 @@ describe('convertParentPipelineAggToColumns', () => { series, metrics: [ { id, field, type: METRIC_TYPES.MAX }, - { id: id1, field: `${id}[75]`, type: METRIC_TYPES.AVG }, - { id: id2, field: `${id1}[50]`, type: TSVB_METRIC_TYPES.MOVING_AVERAGE }, + { id: id1, field: `${id}`, type: METRIC_TYPES.DERIVATIVE }, + { id: id2, field: `${id1}`, type: TSVB_METRIC_TYPES.MOVING_AVERAGE }, ], dataView, }, @@ -476,7 +476,7 @@ describe('convertParentPipelineAggToColumns', () => { { meta: { metricId: 'some-id-2' }, operationType: 'formula', - params: { formula: 'moving_average(average(max(bytes)))' }, + params: { formula: 'moving_average(differences(max(bytes)), window=5)' }, }, ], [ @@ -486,8 +486,8 @@ describe('convertParentPipelineAggToColumns', () => { series, metrics: [ { id, field, type: METRIC_TYPES.MAX }, - { id: id1, field: `${id}[75]`, type: METRIC_TYPES.AVG }, - { id: id2, field: `${id1}[50]`, type: METRIC_TYPES.DERIVATIVE }, + { id: id1, field: `${id}`, type: TSVB_METRIC_TYPES.MOVING_AVERAGE }, + { id: id2, field: `${id1}`, type: METRIC_TYPES.DERIVATIVE }, ], dataView, }, @@ -495,7 +495,7 @@ describe('convertParentPipelineAggToColumns', () => { { meta: { metricId: 'some-id-2' }, operationType: 'formula', - params: { formula: 'differences(average(max(bytes)))' }, + params: { formula: 'differences(moving_average(max(bytes), window=5))' }, }, ], [ diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts index 3b60fe55572a4..3ba9dfcfb6763 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/parent_pipeline.ts @@ -31,9 +31,9 @@ import { Metric } from '../../../../common/types'; import { getFilterRatioFormula, getFormulaFromMetric, - getParentPipelineSeriesFormula, SupportedMetric, SUPPORTED_METRICS, + getPipelineSeriesFormula } from '../metrics'; import { createColumn, getFormat } from './column'; import { createFormulaColumn } from './formula'; @@ -186,7 +186,10 @@ export const computeParentPipelineColumns = ( const aggFormula = getFormulaFromMetric(agg); if (subFunctionMetric.type === 'filter_ratio') { - const script = getFilterRatioFormula(subFunctionMetric, reducedTimeRange); + const script = getFilterRatioFormula(subFunctionMetric, { + reducedTimeRange, + timeShift: series.offset_time, + }); if (!script) { return null; } @@ -235,13 +238,11 @@ const convertMovingAvgOrDerivativeToColumns = ( // support nested aggs with formula const additionalSubFunction = metrics.find(({ id }) => id === nestedFieldId); if (additionalSubFunction || pipelineAgg.name === 'counter_rate') { - const formula = getParentPipelineSeriesFormula( - metrics, - subFunctionMetric, - pipelineAgg, - metric.type, - { metaValue, reducedTimeRange } - ); + const formula = getPipelineSeriesFormula(metric, metrics, subFunctionMetric, { + metaValue, + reducedTimeRange, + timeShift: series.offset_time, + }); if (!formula) { return null; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/std_deviation.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/std_deviation.ts index 73e1b614869b2..d2a18a5dee596 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/std_deviation.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/std_deviation.ts @@ -17,7 +17,10 @@ const createStandartDeviationFormulaColumn = ( metrics: Metric[], reducedTimeRange?: string ) => { - const script = getFormulaEquivalent(metric, metrics, { reducedTimeRange }); + const script = getFormulaEquivalent(metric, metrics, { + reducedTimeRange, + timeShift: series.offset_time, + }); if (!script) return null; return createFormulaColumn(script, { series, metric, dataView }); }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.test.ts index ddf8712de863b..69bfa2a8969a8 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.test.ts @@ -13,7 +13,7 @@ import { TermsParams, } from '@kbn/visualizations-plugin/common/convert_to_lens'; import { createSeries } from '../__mocks__'; -import { converToTermsColumn, convertToTermsParams } from './terms'; +import { convertToTermsColumn, convertToTermsParams } from './terms'; import { Column } from './types'; describe('convertToTermsParams', () => { @@ -208,7 +208,7 @@ describe('converToTermsColumn', () => { test.each< [ string, - Parameters, + Parameters, Partial< Omit & { params: Partial> & { @@ -275,9 +275,9 @@ describe('converToTermsColumn', () => { ], ])('should return %s', (_, input, expected) => { if (expected === null) { - expect(converToTermsColumn(...input)).toBeNull(); + expect(convertToTermsColumn(...input)).toBeNull(); } else { - expect(converToTermsColumn(...input)).toEqual( + expect(convertToTermsColumn(...input)).toEqual( expect.objectContaining({ ...expected, params: expect.objectContaining({ diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts index 3c14efa4f1d6c..977de1947d4f8 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/convert/terms.ts @@ -24,13 +24,12 @@ const getOrderByWithAgg = (series: Series, columns: Column[]): OrderByWithAgg | } if (series.terms_order_by === '_count' || !series.terms_order_by) { - const columnId = uuid(); return { - orderBy: { type: 'column', columnId }, + orderBy: { type: 'custom' }, orderAgg: { operationType: 'count', sourceField: 'document', - columnId, + columnId: uuid(), isBucketed: true, isSplit: false, dataType: 'number', @@ -83,7 +82,7 @@ export const convertToTermsParams = ( }; }; -export const converToTermsColumn = ( +export const convertToTermsColumn = ( termFields: [string, ...string[]], series: Series, columns: Column[], diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.test.ts index a0a995f5d2b45..07f10b472b045 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.test.ts @@ -23,7 +23,8 @@ describe('buildCounterRateFormula', () => { const formula = buildCounterRateFormula( SUPPORTED_METRICS[metric.type]!.name, - dataView.fields[0].name + dataView.fields[0].name, + {} ); expect(formula).toStrictEqual('counter_rate(max(bytes))'); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.ts index 2d1b744c1eb14..78ca3981e4096 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/counter_rate_formula.ts @@ -6,16 +6,23 @@ * Side Public License, v 1. */ -const buildMaxFormula = (selector: string) => { - return `max(${selector})`; +import { addAdditionalArgs } from '.'; +import { AdditionalFormulaArgs } from '../../types'; + +const buildMaxFormula = (selector: string, additionalArgs: AdditionalFormulaArgs) => { + return `max(${selector}${addAdditionalArgs(additionalArgs)})`; }; const buildСounterRateFormula = (aggFormula: string, selector: string) => { return `${aggFormula}(${selector})`; }; -export const buildCounterRateFormula = (aggFormula: string, fieldName: string) => { - const maxFormula = buildMaxFormula(fieldName); +export const buildCounterRateFormula = ( + aggFormula: string, + fieldName: string, + additionalArgs: AdditionalFormulaArgs +) => { + const maxFormula = buildMaxFormula(fieldName, additionalArgs); const counterRateFormula = buildСounterRateFormula(aggFormula, maxFormula); return counterRateFormula; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.test.ts index a18de5cdeba13..652e6ecc22c26 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.test.ts @@ -10,6 +10,7 @@ import { METRIC_TYPES } from '@kbn/data-plugin/public'; import type { Metric } from '../../../../common/types'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; import { getFilterRatioFormula } from './filter_ratio_formula'; +import { AdditionalFormulaArgs } from '../../types'; describe('getFilterRatioFormula', () => { const metric: Metric = { @@ -32,23 +33,28 @@ describe('getFilterRatioFormula', () => { metric_agg: METRIC_TYPES.MEDIAN, }; - test.each<[string, [Metric, string | undefined], string | null]>([ - ['null if metric_agg is not supported', [metricWithNotSupportedMetricAgg, undefined], null], + test.each<[string, [Metric, AdditionalFormulaArgs], string | null]>([ + ['null if metric_agg is not supported', [metricWithNotSupportedMetricAgg, {}], null], [ 'filter ratio formula if metric_agg is not specified', - [metric, undefined], + [metric, {}], "count(kql='*') / count(kql='*')", ], [ 'filter ratio formula if metric_agg is specified', - [metricWithMetricAgg, undefined], + [metricWithMetricAgg, {}], "average('test-1',kql='*') / average('test-1',kql='*')", ], [ 'filter ratio formula if reducedTimeRange is provided', - [metricWithMetricAgg, '1h'], + [metricWithMetricAgg, { reducedTimeRange: '1h' }], "average('test-1',kql='*', reducedTimeRange='1h') / average('test-1',kql='*', reducedTimeRange='1h')", ], + [ + 'filter ratio formula if time shift is provided', + [metricWithMetricAgg, { reducedTimeRange: '1h', timeShift: '3h' }], + "average('test-1',kql='*', shift='3h', reducedTimeRange='1h') / average('test-1',kql='*', shift='3h', reducedTimeRange='1h')", + ], ])('should return %s', (_, input, expected) => { if (expected === null) { expect(getFilterRatioFormula(...input)).toBeNull(); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts index ef16ee9ee2ace..689ba3ca16d1e 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/filter_ratio_formula.ts @@ -9,7 +9,8 @@ import type { Query } from '@kbn/es-query'; import type { Metric, MetricType } from '../../../../common/types'; import { getFormulaFromMetric, SupportedMetric, SUPPORTED_METRICS } from './supported_metrics'; -import { addTimeRangeToFormula } from '.'; +import { addAdditionalArgs } from '.'; +import { AdditionalFormulaArgs } from '../../types'; const escapeQuotes = (str: string) => { return str?.replace(/'/g, "\\'"); @@ -18,16 +19,19 @@ const escapeQuotes = (str: string) => { const constructFilterRationFormula = ( operation: string, metric?: Query, - reducedTimeRange?: string + additionalArgs?: AdditionalFormulaArgs ) => { return `${operation}${metric?.language === 'lucene' ? 'lucene' : 'kql'}='${ metric?.query && typeof metric?.query === 'string' ? escapeQuotes(metric?.query) : metric?.query ?? '*' - }'${addTimeRangeToFormula(reducedTimeRange)})`; + }'${additionalArgs ? addAdditionalArgs(additionalArgs) : ''})`; }; -export const getFilterRatioFormula = (currentMetric: Metric, reducedTimeRange?: string) => { +export const getFilterRatioFormula = ( + currentMetric: Metric, + additionalArgs: AdditionalFormulaArgs +) => { // eslint-disable-next-line @typescript-eslint/naming-convention const { numerator, denominator, metric_agg, field } = currentMetric; let aggregation: SupportedMetric | null | undefined = SUPPORTED_METRICS.count; @@ -42,24 +46,20 @@ export const getFilterRatioFormula = (currentMetric: Metric, reducedTimeRange?: const operation = metric_agg && metric_agg !== 'count' ? `${aggFormula}('${field}',` : 'count('; if (aggregation.name === 'counter_rate') { - const numeratorFormula = `max(${constructFilterRationFormula( - `differences(max('${field}',`, + const numeratorFormula = `counter_rate(${constructFilterRationFormula( + `(max('${field}',`, numerator, - reducedTimeRange + additionalArgs )})`; - const denominatorFormula = `max(${constructFilterRationFormula( - `differences(max('${field}',`, + const denominatorFormula = `counter_rate(${constructFilterRationFormula( + `(max('${field}',`, denominator, - reducedTimeRange + additionalArgs )})`; return `${numeratorFormula}) / ${denominatorFormula})`; } else { - const numeratorFormula = constructFilterRationFormula(operation, numerator, reducedTimeRange); - const denominatorFormula = constructFilterRationFormula( - operation, - denominator, - reducedTimeRange - ); + const numeratorFormula = constructFilterRationFormula(operation, numerator, additionalArgs); + const denominatorFormula = constructFilterRationFormula(operation, denominator, additionalArgs); return `${numeratorFormula} / ${denominatorFormula}`; } }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/index.ts index d03df28f4814e..390154ed98f76 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/index.ts @@ -8,8 +8,7 @@ export * from './supported_metrics'; export * from './metrics_helpers'; -export * from './parent_pipeline_formula'; -export * from './sibling_pipeline_formula'; +export * from './pipeline_formula'; export * from './filter_ratio_formula'; export * from './counter_rate_formula'; export * from './validate_metrics'; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.test.ts index 2b8510d3d348a..c793c9857bdee 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.test.ts @@ -123,7 +123,7 @@ describe('getFormulaEquivalent', () => { [ 'correct formula if metric is parent pipeline agg', [parentPipelineMetric[1], parentPipelineMetric, {}], - 'moving_average(average(test-field-1))', + 'moving_average(average(test-field-1), window=5)', ], ['correct formula if metric is count agg', [countMetric, [countMetric], {}], 'count()'], ['correct formula if metric is static value', [staticValue, [staticValue], {}], '100'], diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts index d6e5c0f8c74b8..374661609b86e 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/metrics_helpers.ts @@ -15,10 +15,10 @@ import { getUISettings } from '../../../services'; import type { Metric, Panel, Series } from '../../../../common/types'; import { TIME_RANGE_DATA_MODES } from '../../../../common/enums'; import { getFilterRatioFormula } from './filter_ratio_formula'; -import { getParentPipelineSeriesFormula } from './parent_pipeline_formula'; -import { getSiblingPipelineSeriesFormula } from './sibling_pipeline_formula'; import { getFormulaFromMetric, SUPPORTED_METRICS } from './supported_metrics'; import { buildCounterRateFormula } from './counter_rate_formula'; +import { getPipelineSeriesFormula } from './pipeline_formula'; +import { AdditionalFormulaArgs } from '../../types'; const shouldCalculateReducedTimeRange = (timeRangeMode?: string) => { return timeRangeMode === TIME_RANGE_DATA_MODES.LAST_VALUE; @@ -68,15 +68,27 @@ export const getTimeScale = (metric: Metric): TimeScaleUnit | undefined => { return timeScale; }; -export const addTimeRangeToFormula = (reducedTimeRange?: string) => { +const addTimeRangeToFormula = (reducedTimeRange?: string) => { return reducedTimeRange ? `, reducedTimeRange='${reducedTimeRange}'` : ''; }; +const addTimeShiftToFormula = (timeShift?: string) => { + return timeShift ? `, shift='${timeShift}'` : ''; +}; + +export const addAdditionalArgs = ({ reducedTimeRange, timeShift }: AdditionalFormulaArgs) => { + return `${addTimeShiftToFormula(timeShift)}${addTimeRangeToFormula(reducedTimeRange)}`; +}; + export const getFormulaEquivalent = ( currentMetric: Metric, metrics: Metric[], - { metaValue, reducedTimeRange }: { metaValue?: number; reducedTimeRange?: string } = {} -) => { + { + metaValue, + reducedTimeRange, + timeShift, + }: { metaValue?: number; reducedTimeRange?: string; timeShift?: string } = {} +): string | null => { const aggregation = SUPPORTED_METRICS[currentMetric.type]; if (!aggregation) { return null; @@ -85,77 +97,77 @@ export const getFormulaEquivalent = ( const aggFormula = getFormulaFromMetric(aggregation); switch (currentMetric.type) { + case 'cumulative_sum': + case 'derivative': + case 'moving_average': case 'avg_bucket': case 'max_bucket': case 'min_bucket': case 'sum_bucket': case 'positive_only': { - return getSiblingPipelineSeriesFormula( - currentMetric.type, - currentMetric, - metrics, - reducedTimeRange - ); + const [subMetricId, nestedMetaValue] = currentMetric?.field?.split('[') ?? []; + const subFunctionMetric = metrics.find((metric) => metric.id === subMetricId); + if (!subFunctionMetric || !SUPPORTED_METRICS[subFunctionMetric.type]) { + return null; + } + + return getPipelineSeriesFormula(currentMetric, metrics, subFunctionMetric, { + metaValue: nestedMetaValue ? Number(nestedMetaValue?.replace(']', '')) : undefined, + reducedTimeRange, + timeShift, + }); } case 'count': { - return `${aggFormula}()`; + return `${aggFormula}(${timeShift ? `shift='${timeShift}'` : ''}${ + timeShift && reducedTimeRange ? ', ' : '' + }${reducedTimeRange ? `reducedTimeRange='${reducedTimeRange}'` : ''})`; } case 'percentile': { return `${aggFormula}(${currentMetric.field}${ metaValue ? `, percentile=${metaValue}` : '' - }${addTimeRangeToFormula(reducedTimeRange)})`; + }${addAdditionalArgs({ reducedTimeRange, timeShift })})`; } case 'percentile_rank': { return `${aggFormula}(${currentMetric.field}${ metaValue ? `, value=${metaValue}` : '' - }${addTimeRangeToFormula(reducedTimeRange)})`; - } - case 'cumulative_sum': - case 'derivative': - case 'moving_average': { - const [fieldId, _] = currentMetric?.field?.split('[') ?? []; - const subFunctionMetric = metrics.find((metric) => metric.id === fieldId); - if (!subFunctionMetric) { - return null; - } - const pipelineAgg = SUPPORTED_METRICS[subFunctionMetric.type]; - if (!pipelineAgg) { - return null; - } - return getParentPipelineSeriesFormula( - metrics, - subFunctionMetric, - pipelineAgg, - currentMetric.type, - { metaValue, reducedTimeRange } - ); + }${addAdditionalArgs({ reducedTimeRange, timeShift })})`; } case 'positive_rate': { - return buildCounterRateFormula(aggFormula, currentMetric.field!); + return buildCounterRateFormula(aggFormula, currentMetric.field!, { + reducedTimeRange, + timeShift, + }); } case 'filter_ratio': { - return getFilterRatioFormula(currentMetric, reducedTimeRange); + return getFilterRatioFormula(currentMetric, { reducedTimeRange, timeShift }); } case 'static': { return `${currentMetric.value}`; } case 'std_deviation': { if (currentMetric.mode === 'lower') { - return `average(${currentMetric.field}${addTimeRangeToFormula(reducedTimeRange)}) - ${ - currentMetric.sigma || 1.5 - } * ${aggFormula}(${currentMetric.field}${addTimeRangeToFormula(reducedTimeRange)})`; + return `average(${currentMetric.field}${addAdditionalArgs({ + reducedTimeRange, + timeShift, + })}) - ${currentMetric.sigma || 1.5} * ${aggFormula}(${ + currentMetric.field + }${addAdditionalArgs({ reducedTimeRange, timeShift })})`; } if (currentMetric.mode === 'upper') { - return `average(${currentMetric.field}${addTimeRangeToFormula(reducedTimeRange)}) + ${ - currentMetric.sigma || 1.5 - } * ${aggFormula}(${currentMetric.field}${addTimeRangeToFormula(reducedTimeRange)})`; + return `average(${currentMetric.field}${addAdditionalArgs({ + reducedTimeRange, + timeShift, + })}) + ${currentMetric.sigma || 1.5} * ${aggFormula}(${ + currentMetric.field + }${addAdditionalArgs({ reducedTimeRange, timeShift })})`; } return `${aggFormula}(${currentMetric.field})`; } default: { - return `${aggFormula}(${currentMetric.field ?? ''}${addTimeRangeToFormula( - reducedTimeRange - )})`; + return `${aggFormula}(${currentMetric.field ?? ''}${addAdditionalArgs({ + reducedTimeRange, + timeShift, + })})`; } } }; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.ts deleted file mode 100644 index c74ce9713184a..0000000000000 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.ts +++ /dev/null @@ -1,68 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { Metric, MetricType } from '../../../../common/types'; -import { SUPPORTED_METRICS, getFormulaFromMetric, SupportedMetric } from './supported_metrics'; -import { getFormulaEquivalent } from './metrics_helpers'; - -export const getParentPipelineSeriesFormula = ( - metrics: Metric[], - subFunctionMetric: Metric, - pipelineAgg: SupportedMetric, - aggregation: MetricType, - { metaValue, reducedTimeRange }: { metaValue?: number; reducedTimeRange?: string } = {} -) => { - let formula = ''; - const aggregationMap = SUPPORTED_METRICS[aggregation]; - if (!aggregationMap) { - return null; - } - if (subFunctionMetric.type === 'static') { - return null; - } - - const aggFormula = getFormulaFromMetric(aggregationMap); - const pipelineFormula = getFormulaFromMetric(pipelineAgg); - - const subMetricField = subFunctionMetric.field; - const [nestedFieldId, nestedMeta] = subMetricField?.split('[') ?? []; - // support nested aggs - const additionalSubFunction = metrics.find((metric) => metric.id === nestedFieldId); - if (additionalSubFunction) { - // support nested aggs with formula - const additionalPipelineAggMap = SUPPORTED_METRICS[additionalSubFunction.type]; - if (!additionalPipelineAggMap) { - return null; - } - const additionalPipelineAggFormula = getFormulaFromMetric(additionalPipelineAggMap); - - const nestedMetaValue = Number(nestedMeta?.replace(']', '')); - let additionalFunctionArgs; - if (additionalPipelineAggMap.name === 'percentile' && nestedMetaValue) { - additionalFunctionArgs = `, percentile=${nestedMetaValue}`; - } - if (additionalPipelineAggMap.name === 'percentile_rank' && nestedMetaValue) { - additionalFunctionArgs = `, value=${nestedMetaValue}`; - } - formula = `${aggFormula}(${pipelineFormula}(${additionalPipelineAggFormula}(${ - additionalSubFunction.field ?? '' - }${additionalFunctionArgs ?? ''})))`; - } else { - const subFormula = getFormulaEquivalent(subFunctionMetric, metrics, { - metaValue, - reducedTimeRange, - }); - - if (!subFormula) { - return null; - } - - formula = `${aggregationMap.name}(${subFormula})`; - } - return formula; -}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.test.ts similarity index 74% rename from src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.test.ts rename to src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.test.ts index 5949a60fa76a6..07af0740d648b 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/parent_pipeline_formula.test.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.test.ts @@ -7,10 +7,9 @@ */ import { METRIC_TYPES } from '@kbn/data-plugin/public'; -import type { Metric, MetricType } from '../../../../common/types'; +import type { Metric } from '../../../../common/types'; import { TSVB_METRIC_TYPES } from '../../../../common/enums'; -import { getParentPipelineSeriesFormula } from './parent_pipeline_formula'; -import { SupportedMetric, SUPPORTED_METRICS } from './supported_metrics'; +import { getPipelineSeriesFormula } from './pipeline_formula'; describe('getParentPipelineSeriesFormula', () => { const metrics: Metric[] = [ @@ -98,20 +97,37 @@ describe('getParentPipelineSeriesFormula', () => { }, ]; + const positiveOnlyMetrics: Metric[] = [ + { + id: 'test-1', + type: METRIC_TYPES.AVG, + field: 'test-field-1', + }, + { + id: 'some-random-value', + type: TSVB_METRIC_TYPES.POSITIVE_ONLY, + field: 'test-1', + }, + ]; + test.each< [ string, - [Metric[], Metric, SupportedMetric, MetricType, { metaValue?: number; window?: string }], + [ + Metric, + Metric[], + Metric, + { metaValue?: number; reducedTimeRange?: string; timeShift?: string } + ], string | null ] >([ [ 'null if metric is not supported', [ + metricsWithNotSupportedSubFunction[0], metrics, metrics[0], - SUPPORTED_METRICS[metrics[0].type]!, - TSVB_METRIC_TYPES.SUM_OF_SQUARES_BUCKET, {}, ], null, @@ -119,10 +135,9 @@ describe('getParentPipelineSeriesFormula', () => { [ 'null if metric have not supported additional sub function', [ + metricsWithNotSupportedSubFunction[2], metricsWithNotSupportedSubFunction, metricsWithNotSupportedSubFunction[1], - SUPPORTED_METRICS[metricsWithNotSupportedSubFunction[1].type]!, - TSVB_METRIC_TYPES.MOVING_AVERAGE, {}, ], null, @@ -130,51 +145,52 @@ describe('getParentPipelineSeriesFormula', () => { [ 'correct formula if metric is supported', [ + metrics[1], metrics, metrics[0], - SUPPORTED_METRICS[metrics[0].type]!, - TSVB_METRIC_TYPES.MOVING_AVERAGE, {}, ], - 'moving_average(average(test-field-1))', + 'moving_average(average(test-field-1), window=5)', ], [ 'correct formula if metric have additional sub function', [ + metricsWithSubFunction[2], metricsWithSubFunction, metricsWithSubFunction[1], - SUPPORTED_METRICS[metricsWithSubFunction[1].type]!, - TSVB_METRIC_TYPES.MOVING_AVERAGE, {}, ], - 'moving_average(differences(average(test-field-1)))', + 'moving_average(differences(average(test-field-1)), window=5)', ], [ 'correct formula if metric have percentile additional sub function', [ + metricsWithPercentileSubFunction[2], metricsWithPercentileSubFunction, metricsWithPercentileSubFunction[1], - SUPPORTED_METRICS[metricsWithPercentileSubFunction[1].type]!, - TSVB_METRIC_TYPES.MOVING_AVERAGE, {}, ], - 'moving_average(differences(percentile(test-field-1, percentile=50)))', + 'moving_average(differences(percentile(test-field-1, percentile=50)), window=5)', ], [ 'correct formula if metric have percentile rank additional sub function', [ + metricsWithPercentileRankSubFunction[2], metricsWithPercentileRankSubFunction, metricsWithPercentileRankSubFunction[1], - SUPPORTED_METRICS[metricsWithPercentileRankSubFunction[1].type]!, - TSVB_METRIC_TYPES.MOVING_AVERAGE, {}, ], - 'moving_average(differences(percentile_rank(test-field-1, value=5)))', + 'moving_average(differences(percentile_rank(test-field-1, value=5)), window=5)', + ], + [ + 'correct formula if metric is positive only', + [positiveOnlyMetrics[1], positiveOnlyMetrics, positiveOnlyMetrics[0], {}], + 'pick_max(average(test-field-1), 0)', ], ])('should return %s', (_, input, expected) => { if (expected === null) { - expect(getParentPipelineSeriesFormula(...input)).toBeNull(); + expect(getPipelineSeriesFormula(...input)).toBeNull(); } - expect(getParentPipelineSeriesFormula(...input)).toEqual(expected); + expect(getPipelineSeriesFormula(...input)).toEqual(expected); }); }); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts new file mode 100644 index 0000000000000..d357d886ff5bd --- /dev/null +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/pipeline_formula.ts @@ -0,0 +1,58 @@ +/* + * 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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { TSVB_METRIC_TYPES } from '../../../../common/enums'; +import type { Metric } from '../../../../common/types'; +import { getFormulaFromMetric, SUPPORTED_METRICS } from './supported_metrics'; +import { getFormulaEquivalent } from './metrics_helpers'; + +const getAdditionalArgs = (metric: Metric) => { + if (metric.type === TSVB_METRIC_TYPES.POSITIVE_ONLY) { + return `, 0`; + } + + if (metric.type === TSVB_METRIC_TYPES.MOVING_AVERAGE) { + return `, window=${metric.window || 5}`; + } + + return ''; +}; + +export const getPipelineSeriesFormula = ( + metric: Metric, + metrics: Metric[], + subFunctionMetric: Metric, + { + metaValue, + reducedTimeRange, + timeShift, + }: { metaValue?: number; reducedTimeRange?: string; timeShift?: string } = {} +) => { + const aggregationMap = SUPPORTED_METRICS[metric.type]; + if (!aggregationMap) { + return null; + } + if (!subFunctionMetric || subFunctionMetric.type === 'static') { + return null; + } + + const aggFormula = getFormulaFromMetric(aggregationMap); + + const subFormula = getFormulaEquivalent(subFunctionMetric, metrics, { + metaValue, + reducedTimeRange, + timeShift, + }); + + if (!subFormula) { + return null; + } + const additionalArgs = getAdditionalArgs(metric); + + return `${aggFormula}(${subFormula}${additionalArgs})`; +}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.test.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.test.ts deleted file mode 100644 index 15c1df306c05a..0000000000000 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.test.ts +++ /dev/null @@ -1,114 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { METRIC_TYPES } from '@kbn/data-plugin/public'; -import type { Metric, MetricType } from '../../../../common/types'; -import { TSVB_METRIC_TYPES } from '../../../../common/enums'; -import { getSiblingPipelineSeriesFormula } from './sibling_pipeline_formula'; - -describe('getSiblingPipelineSeriesFormula', () => { - const metrics: Metric[] = [ - { - id: 'test-1', - type: METRIC_TYPES.AVG, - field: 'test-field-1', - }, - { - id: 'some-random-value', - type: METRIC_TYPES.AVG_BUCKET, - field: 'test-1', - }, - ]; - - const positiveOnlyMetrics: Metric[] = [ - { - id: 'test-1', - type: METRIC_TYPES.AVG, - field: 'test-field-1', - }, - { - id: 'some-random-value', - type: TSVB_METRIC_TYPES.POSITIVE_ONLY, - field: 'test-1', - }, - ]; - - const metricsWithNotSupportedSubFunction: Metric[] = [ - { - id: 'test-2', - type: METRIC_TYPES.MEDIAN, - field: 'test-field-1', - }, - { - id: 'test-1', - type: METRIC_TYPES.SUM_BUCKET, - field: 'test-2', - }, - { - id: 'some-random-value', - type: METRIC_TYPES.AVG_BUCKET, - field: 'test-1', - }, - ]; - - const metricsWithSubFunction: Metric[] = [ - { - id: 'test-2', - type: METRIC_TYPES.AVG, - field: 'test-field-1', - }, - { - id: 'test-1', - type: METRIC_TYPES.SUM_BUCKET, - field: 'test-2', - }, - { - id: 'some-random-value', - type: METRIC_TYPES.AVG_BUCKET, - field: 'test-1', - }, - ]; - - test.each<[string, [MetricType, Metric, Metric[], string | undefined], string | null]>([ - [ - 'null if metric is not supported', - [TSVB_METRIC_TYPES.SUM_OF_SQUARES_BUCKET, metrics[1], metrics, undefined], - null, - ], - [ - 'null if metric have not supported additional sub function', - [ - METRIC_TYPES.AVG_BUCKET, - metricsWithNotSupportedSubFunction[2], - metricsWithNotSupportedSubFunction, - undefined, - ], - null, - ], - [ - 'correct formula if metric is supported', - [METRIC_TYPES.AVG_BUCKET, metrics[1], metrics, undefined], - 'overall_average(average(test-field-1))', - ], - [ - 'correct formula if metric is positive only', - [TSVB_METRIC_TYPES.POSITIVE_ONLY, positiveOnlyMetrics[1], positiveOnlyMetrics, undefined], - 'pick_max(average(test-field-1), 0)', - ], - [ - 'correct formula if metric have additional sub function', - [METRIC_TYPES.AVG_BUCKET, metricsWithSubFunction[2], metricsWithSubFunction, undefined], - 'overall_average(overall_sum(average(test-field-1)))', - ], - ])('should return %s', (_, input, expected) => { - if (expected === null) { - expect(getSiblingPipelineSeriesFormula(...input)).toBeNull(); - } - expect(getSiblingPipelineSeriesFormula(...input)).toEqual(expected); - }); -}); diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.ts deleted file mode 100644 index 83730071f7baa..0000000000000 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/metrics/sibling_pipeline_formula.ts +++ /dev/null @@ -1,71 +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 - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { Metric, MetricType } from '../../../../common/types'; -import { getFormulaFromMetric, SUPPORTED_METRICS } from './supported_metrics'; -import { getFormulaEquivalent } from './metrics_helpers'; - -export const getSiblingPipelineSeriesFormula = ( - aggregation: MetricType, - currentMetric: Metric, - metrics: Metric[], - reducedTimeRange?: string -) => { - const [nestedFieldId, nestedMeta] = currentMetric.field?.split('[') ?? []; - const subFunctionMetric = metrics.find((metric) => metric.id === nestedFieldId); - if (!subFunctionMetric || subFunctionMetric.type === 'static') { - return null; - } - const pipelineAggMap = SUPPORTED_METRICS[subFunctionMetric.type]; - if (!pipelineAggMap) { - return null; - } - const pipelineAggFormula = getFormulaFromMetric(pipelineAggMap); - - const aggregationMap = SUPPORTED_METRICS[aggregation]; - if (!aggregationMap) { - return null; - } - const aggFormula = getFormulaFromMetric(aggregationMap); - - const subMetricField = subFunctionMetric.type !== 'count' ? subFunctionMetric.field : ''; - // support nested aggs with formula - const additionalSubFunction = metrics.find((metric) => metric.id === subMetricField); - let formula = `${aggFormula}(`; - let minimumValue = ''; - if (currentMetric.type === 'positive_only') { - minimumValue = `, 0`; - } - if (additionalSubFunction) { - const additionalPipelineAggMap = SUPPORTED_METRICS[additionalSubFunction.type]; - if (!additionalPipelineAggMap) { - return null; - } - const additionalPipelineAggFormula = getFormulaFromMetric(additionalPipelineAggMap); - - const additionalSubFunctionField = - additionalSubFunction.type !== 'count' ? additionalSubFunction.field : ''; - formula += `${pipelineAggFormula}(${additionalPipelineAggFormula}(${ - additionalSubFunctionField ?? '' - }))${minimumValue})`; - } else { - const nestedMetaValue = Number(nestedMeta?.replace(']', '')); - - const subFormula = getFormulaEquivalent(subFunctionMetric, metrics, { - metaValue: nestedMetaValue, - reducedTimeRange, - }); - - if (!subFormula) { - return null; - } - - formula += `${subFormula}${minimumValue})`; - } - return formula; -}; diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts index 967702abbd88a..c0aa201de6837 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/lib/series/buckets_columns.ts @@ -13,7 +13,7 @@ import { Column, convertToFiltersColumn, convertToDateHistogramColumn, - converToTermsColumn, + convertToTermsColumn, } from '../convert'; import { getValidColumns } from './columns'; @@ -68,7 +68,7 @@ export const getBucketsColumns = ( return null; } - const termsColumn = converToTermsColumn( + const termsColumn = convertToTermsColumn( splitFields as [string, ...string[]], series, columns, diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts index 6cda563b6d85a..c3f5900b35eb3 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/timeseries/index.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { parseTimeShift } from '@kbn/data-plugin/common'; import { Layer } from '@kbn/visualizations-plugin/common/convert_to_lens'; import uuid from 'uuid'; import { Panel } from '../../../common/types'; @@ -46,6 +47,11 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model: Panel continue; } + // not valid time shift + if (series.offset_time && parseTimeShift(series.offset_time) === 'invalid') { + return null; + } + if (!isValidMetrics(series.metrics, PANEL_TYPES.TIMESERIES)) { return null; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts index 137f457bad307..1afbd89e7027f 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts @@ -7,6 +7,7 @@ */ import uuid from 'uuid'; +import { parseTimeShift } from '@kbn/data-plugin/common'; import { Layer } from '@kbn/visualizations-plugin/common/convert_to_lens'; import { PANEL_TYPES } from '../../../common/enums'; import { getDataViewsStart } from '../../services'; @@ -38,6 +39,11 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeR continue; } + // not valid time shift + if (series.offset_time && parseTimeShift(series.offset_time) === 'invalid') { + return null; + } + if (!isValidMetrics(series.metrics, PANEL_TYPES.TOP_N, series.time_range_mode)) { return null; } diff --git a/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts b/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts index bdafc6999772d..d91e801aec9d7 100644 --- a/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts +++ b/src/plugins/vis_types/timeseries/public/convert_to_lens/types.ts @@ -25,3 +25,8 @@ export type ConvertToColumnsFn = ( { series: Series, metric: Metric, dataView: DataView }: CommonColumnConverterArgs, reducedTimeRange?: string ) => Array | null; + +export interface AdditionalFormulaArgs { + reducedTimeRange?: string; + timeShift?: string; +} diff --git a/src/plugins/visualizations/common/convert_to_lens/types/common.ts b/src/plugins/visualizations/common/convert_to_lens/types/common.ts index 91522da911b02..974326834ce2a 100644 --- a/src/plugins/visualizations/common/convert_to_lens/types/common.ts +++ b/src/plugins/visualizations/common/convert_to_lens/types/common.ts @@ -41,7 +41,7 @@ export interface Range { export interface NumberValueFormat { id: string; params?: { - decimals?: number; + decimals: number; suffix?: string; }; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts index b7a41b1a3ad1f..64ae3e3b59d43 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/indexpattern_suggestions.ts @@ -233,7 +233,8 @@ function getParams(column: Column) { function getIncompleteParams(column: Column) { return { filter: column.filter, - shift: column.timeShift, + timeShift: column.timeShift, + timeScale: column.timeScale, dataType: column.dataType, ...(column.reducedTimeRange && { reducedTimeRange: column.reducedTimeRange }), }; @@ -274,13 +275,29 @@ function convertToColumnChange(columns: Layer['columns'], indexPattern: IndexPat if ( isTermsColumn(column) && column.params.orderAgg && + newColumn.columnParams && !columns.some((c) => c.columnId === column.params.orderAgg?.columnId) ) { - const orderAggColumn: ColumnChange = createColumnChange( - column.params.orderAgg, - indexPattern + const orderColumn = column.params.orderAgg; + const operationDefinition = operationDefinitionMap[orderColumn.operationType]; + const layer: IndexPatternLayer = { + indexPatternId: indexPattern.id, + columns: {}, + columnOrder: [], + }; + newColumn.columnParams.orderAgg = operationDefinition.buildColumn( + { + previousColumn: { + ...column.params.orderAgg, + label: column.params.orderAgg?.label || '', + }, + indexPattern, + layer, + referenceIds: [], + field: getFieldWithLabel(column.params.orderAgg, indexPattern)!, + }, + column.params ); - acc.push(orderAggColumn); } acc.push(newColumn); } @@ -310,7 +327,7 @@ function createNewLayerWithMetricAggregationFromVizEditor( { previousColumn: { ...previousColumn, - label: previousColumn?.label || '', + label: previousColumn?.label || (column.columnParams?.formula as string) || '', }, indexPattern, layer: newLayer, @@ -329,7 +346,13 @@ function createNewLayerWithMetricAggregationFromVizEditor( }); let updatedLayer = newLayer; layer.columns.forEach(({ columnId, label: customLabel }) => { - updatedLayer = updateColumnLabel({ layer: updatedLayer, columnId, customLabel }); + if (customLabel) { + updatedLayer = updateColumnLabel({ + layer: updatedLayer, + columnId, + customLabel: isReferenced(updatedLayer, columnId) ? '' : customLabel, + }); + } }); return updatedLayer; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index eec39bd530944..0427e40f24ac6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -235,6 +235,7 @@ export const termsOperation: OperationDefinition< columnId: existingMetricColumn, } : { type: 'alphabetical', fallback: true }), + orderAgg: columnParams?.orderBy.type === 'custom' ? columnParams?.orderAgg : undefined, orderDirection: columnParams?.orderDirection ?? (existingMetricColumn ? 'desc' : 'asc'), otherBucket: (columnParams?.otherBucket ?? true) && !indexPattern.hasRestrictions, missingBucket: columnParams?.missingBucket ?? false, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts index 8ff993da47474..30e3b89f8b6d3 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/layer_helpers.ts @@ -214,6 +214,8 @@ const insertReferences = ({ op: operation.type, indexPattern, columnParams: { ...reference.columnParams }, + incompleteParams: reference.incompleteParams, + initialParams: reference.initialParams, ...(reference.references ? { references: reference.references } : {}), visualizationGroups, targetGroup, @@ -238,6 +240,8 @@ const insertReferences = ({ op: operation.type, indexPattern, field, + incompleteParams: reference.incompleteParams, + initialParams: reference.initialParams, columnParams: { ...reference.columnParams }, visualizationGroups, targetGroup, @@ -1282,7 +1286,7 @@ export function updateColumnLabel({ ...layer.columns, [columnId]: { ...oldColumn, - label: customLabel ? customLabel : oldColumn.label, + label: customLabel !== undefined ? customLabel : oldColumn.label, customLabel: Boolean(customLabel), }, } as Record,