From d4837cf0f06e9f477c8846782a88b6a24aa4a119 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Mon, 15 Feb 2021 10:50:07 +0100 Subject: [PATCH 1/7] pass interval through --- .../search/aggs/buckets/histogram.test.ts | 23 +++++ .../common/search/aggs/buckets/histogram.ts | 27 ++++++ .../get_number_histogram_interval.test.ts | 96 +++++++++++++++++++ .../utils/get_number_histogram_interval.ts | 48 ++++++++++ .../data/common/search/aggs/utils/index.ts | 1 + src/plugins/data/public/index.ts | 2 + .../__snapshots__/expression.test.tsx.snap | 49 ++++++++++ .../xy_visualization/expression.test.tsx | 42 +++++++- .../public/xy_visualization/expression.tsx | 29 +++--- 9 files changed, 304 insertions(+), 13 deletions(-) create mode 100644 src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts create mode 100644 src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts index bddc7060af440..515dfed0c6c4c 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts @@ -12,6 +12,8 @@ import { AggTypesDependencies } from '../agg_types'; import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketHistogramAggConfig, getHistogramBucketAgg, AutoBounds } from './histogram'; import { BucketAggType } from './bucket_agg_type'; +import { SerializableState } from 'src/plugins/expressions/common'; +import { isSerializedAutoInterval } from '../utils/get_number_histogram_interval'; describe('Histogram Agg', () => { let aggTypesDependencies: AggTypesDependencies; @@ -230,6 +232,27 @@ describe('Histogram Agg', () => { expect(params.interval).toBeNaN(); }); + test('will serialize the auto interval along with the actually chosen interval and deserialize correctly', () => { + const aggConfigs = getAggConfigs({ + interval: 'auto', + field: { + name: 'field', + }, + }); + (aggConfigs.aggs[0] as IBucketHistogramAggConfig).setAutoBounds({ min: 0, max: 1000 }); + const serializedAgg = aggConfigs.aggs[0].serialize(); + const serializedIntervalParam = (serializedAgg.params as SerializableState).interval; + expect(isSerializedAutoInterval(serializedIntervalParam as string | number)).toBe(true); + const freshHistogramAggConfig = getAggConfigs({ + interval: 100, + field: { + name: 'field', + }, + }).aggs[0]; + freshHistogramAggConfig.setParams(serializedAgg.params); + expect(freshHistogramAggConfig.getParam('interval')).toEqual('auto'); + }); + describe('interval scaling', () => { const getInterval = ( maxBars: number, diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.ts b/src/plugins/data/common/search/aggs/buckets/histogram.ts index 5d6d7d509f08e..c3290b5cf18db 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.ts @@ -20,6 +20,10 @@ import { aggHistogramFnName } from './histogram_fn'; import { ExtendedBounds } from './lib/extended_bounds'; import { isAutoInterval, autoInterval } from './_interval_options'; import { calculateHistogramInterval } from './lib/histogram_calculate_interval'; +import { + buildSerializedAutoInterval, + isSerializedAutoInterval, +} from '../utils/get_number_histogram_interval'; export interface AutoBounds { min: number; @@ -152,6 +156,29 @@ export const getHistogramBucketAgg = ({ esTypes: aggConfig.params.field?.spec?.esTypes || [], }); }, + serialize(val, aggConfig) { + // store actually used auto interval in serialized agg config to be able to read it from the result data table meta information + const autoBounds = aggConfig?.getAutoBounds(); + if (aggConfig && autoBounds) { + const usedInterval = calculateHistogramInterval({ + values: autoBounds, + interval: aggConfig.params.interval, + maxBucketsUiSettings: getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), + maxBucketsUserInput: aggConfig.params.maxBars, + intervalBase: aggConfig.params.intervalBase, + esTypes: aggConfig.params.field?.spec?.esTypes || [], + }); + return buildSerializedAutoInterval(usedInterval); + } else { + return val; + } + }, + deserialize(val) { + if (isSerializedAutoInterval(val)) { + return autoInterval; + } + return val; + }, }, { name: 'maxBars', diff --git a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts new file mode 100644 index 0000000000000..afa7cf2ef2dc2 --- /dev/null +++ b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts @@ -0,0 +1,96 @@ +/* + * 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 { getNumberHistogramIntervalByDatatableColumn } from '.'; +import { BUCKET_TYPES } from '../buckets'; + +describe('getNumberHistogramIntervalByDatatableColumn', () => { + it('returns nothing on column from other data source', () => { + expect( + getNumberHistogramIntervalByDatatableColumn({ + id: 'test', + name: 'test', + meta: { + type: 'date', + source: 'essql', + }, + }) + ).toEqual(undefined); + }); + + it('returns nothing on non histogram column', () => { + expect( + getNumberHistogramIntervalByDatatableColumn({ + id: 'test', + name: 'test', + meta: { + type: 'date', + source: 'esaggs', + sourceParams: { + type: BUCKET_TYPES.TERMS, + }, + }, + }) + ).toEqual(undefined); + }); + + it('returns interval on resolved auto interval', () => { + expect( + getNumberHistogramIntervalByDatatableColumn({ + id: 'test', + name: 'test', + meta: { + type: 'date', + source: 'esaggs', + sourceParams: { + type: BUCKET_TYPES.HISTOGRAM, + params: { + interval: 'auto$$$20', + }, + }, + }, + }) + ).toEqual(20); + }); + + it('returns interval on fixed interval', () => { + expect( + getNumberHistogramIntervalByDatatableColumn({ + id: 'test', + name: 'test', + meta: { + type: 'date', + source: 'esaggs', + sourceParams: { + type: BUCKET_TYPES.HISTOGRAM, + params: { + interval: 7, + }, + }, + }, + }) + ).toEqual(7); + }); + + it('returns undefined if information is not available', () => { + expect( + getNumberHistogramIntervalByDatatableColumn({ + id: 'test', + name: 'test', + meta: { + type: 'date', + source: 'esaggs', + sourceParams: { + type: BUCKET_TYPES.HISTOGRAM, + params: {}, + }, + }, + }) + ).toEqual(undefined); + }); +}); diff --git a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts new file mode 100644 index 0000000000000..4e753ebaa2cd4 --- /dev/null +++ b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts @@ -0,0 +1,48 @@ +/* + * 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 { DatatableColumn } from 'src/plugins/expressions/common'; +import type { AggParamsHistogram } from '../buckets'; +import { BUCKET_TYPES } from '../buckets/bucket_agg_types'; + +const SEPARATOR = '$$$'; + +function parseSerializedInterval(interval: string | number) { + if (typeof interval === 'number') { + return interval; + } + if (interval === 'auto') { + return 'auto'; + } + return Number(interval.split(SEPARATOR)[1]); +} + +export function buildSerializedAutoInterval(usedInterval: number) { + return `auto${SEPARATOR}${usedInterval}`; +} + +export function isSerializedAutoInterval(interval: string | number) { + return typeof interval === 'string' && interval.startsWith('auto'); +} + +/** + * Helper function returning the used interval for data table column created by the histogramm agg type. + * "auto" will get expanded to the actually used interval. + * If the column is not a column created by a histogram aggregation of the esaggs data source, + * this function will return undefined. + */ +export const getNumberHistogramIntervalByDatatableColumn = (column: DatatableColumn) => { + if (column.meta.source !== 'esaggs') return; + if (column.meta.sourceParams?.type !== BUCKET_TYPES.HISTOGRAM) return; + const params = (column.meta.sourceParams.params as unknown) as AggParamsHistogram; + + if (!params.interval) { + return undefined; + } + return parseSerializedInterval(params.interval); +}; diff --git a/src/plugins/data/common/search/aggs/utils/index.ts b/src/plugins/data/common/search/aggs/utils/index.ts index 40451a0f66e0c..f90e8f88546f4 100644 --- a/src/plugins/data/common/search/aggs/utils/index.ts +++ b/src/plugins/data/common/search/aggs/utils/index.ts @@ -7,6 +7,7 @@ */ export * from './calculate_auto_time_expression'; +export { getNumberHistogramIntervalByDatatableColumn } from './get_number_histogram_interval'; export * from './date_interval_utils'; export * from './get_format_with_aggs'; export * from './ipv4_address'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 83a248ee2c3de..73c868bebaace 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -308,6 +308,7 @@ import { parseInterval, toAbsoluteDates, boundsDescendingRaw, + getNumberHistogramIntervalByDatatableColumn, // expressions utils getRequestInspectorStats, getResponseInspectorStats, @@ -416,6 +417,7 @@ export const search = { termsAggFilter, toAbsoluteDates, boundsDescendingRaw, + getNumberHistogramIntervalByDatatableColumn, }, getRequestInspectorStats, getResponseInspectorStats, diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap index a2047b7bae669..9a32f1c331152 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/expression.test.tsx.snap @@ -26,6 +26,13 @@ exports[`xy_expression XYChart component it renders area 1`] = ` "headerFormatter": [Function], } } + xDomain={ + Object { + "max": undefined, + "min": undefined, + "minInterval": 50, + } + } /> { }} /> ); - expect(component.find(Settings).prop('xDomain')).toBeUndefined(); + const xDomain = component.find(Settings).prop('xDomain'); + expect(xDomain).toEqual( + expect.objectContaining({ + min: undefined, + max: undefined, + }) + ); + }); + + test('it uses min interval if passed in', () => { + const { data, args } = sampleArgs(); + + const component = shallow( + + ); + expect(component.find(Settings).prop('xDomain')).toEqual({ minInterval: 101 }); }); test('it renders bar', () => { @@ -1881,6 +1904,23 @@ describe('xy_expression', () => { expect(result).toEqual(5 * 60 * 1000); }); + it('should return interval of number histogram if available on first x axis columns', async () => { + xyProps.args.layers[0].xScaleType = 'linear'; + xyProps.data.tables.first.columns[2].meta = { + source: 'esaggs', + type: 'number', + field: 'someField', + sourceParams: { + type: 'histogram', + params: { + interval: 'auto$$$5', + }, + }, + }; + const result = await calculateMinInterval(xyProps, jest.fn().mockResolvedValue(undefined)); + expect(result).toEqual(5); + }); + it('should return undefined if data table is empty', async () => { xyProps.data.tables.first.rows = []; const result = await calculateMinInterval( diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 7f6414b40cb90..eda08715b394e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -199,13 +199,20 @@ export async function calculateMinInterval( const filteredLayers = getFilteredLayers(layers, data); if (filteredLayers.length === 0) return; const isTimeViz = data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time'); - - if (!isTimeViz) return; - const dateColumn = data.tables[filteredLayers[0].layerId].columns.find( + const xColumn = data.tables[filteredLayers[0].layerId].columns.find( (column) => column.id === filteredLayers[0].xAccessor ); - if (!dateColumn) return; - const dateMetaData = await getIntervalByColumn(dateColumn); + + if (!xColumn) return; + if (!isTimeViz) { + const histogramInterval = search.aggs.getNumberHistogramIntervalByDatatableColumn(xColumn); + if (typeof histogramInterval === 'number') { + return histogramInterval; + } else { + return undefined; + } + } + const dateMetaData = await getIntervalByColumn(xColumn); if (!dateMetaData) return; const intervalDuration = search.aggs.parseInterval(dateMetaData.interval); if (!intervalDuration) return; @@ -381,13 +388,11 @@ export function XYChart({ const isTimeViz = data.dateRange && filteredLayers.every((l) => l.xScaleType === 'time'); const isHistogramViz = filteredLayers.every((l) => l.isHistogram); - const xDomain = isTimeViz - ? { - min: data.dateRange?.fromDate.getTime(), - max: data.dateRange?.toDate.getTime(), - minInterval, - } - : undefined; + const xDomain = { + min: isTimeViz ? data.dateRange?.fromDate.getTime() : undefined, + max: isTimeViz ? data.dateRange?.toDate.getTime() : undefined, + minInterval, + }; const getYAxesTitles = ( axisSeries: Array<{ layer: string; accessor: string }>, From 14242b25a5bc42b730bb9aa006b47d23377066fb Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Mon, 15 Feb 2021 13:17:53 +0100 Subject: [PATCH 2/7] update docs --- ...ibana-plugin-plugins-data-public.search.md | 1 + src/plugins/data/public/public.api.md | 31 ++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md index 4b3c915b49c2d..53e58528a6a4f 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -46,6 +46,7 @@ search: { boundLabel: string; intervalLabel: string; })[]; + getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | "auto" | undefined; }; getRequestInspectorStats: typeof getRequestInspectorStats; getResponseInspectorStats: typeof getResponseInspectorStats; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 4668ce2208610..402321d9c79c1 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2232,6 +2232,7 @@ export const search: { boundLabel: string; intervalLabel: string; })[]; + getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | "auto" | undefined; }; getRequestInspectorStats: typeof getRequestInspectorStats; getResponseInspectorStats: typeof getResponseInspectorStats; @@ -2607,21 +2608,21 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:399:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:409:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:416:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:417:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:420:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:421:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:424:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:417:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:418:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:421:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:422:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:425:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/search/session/session_service.ts:42:5 - (ae-forgotten-export) The symbol "UrlGeneratorStateMapping" needs to be exported by the entry point index.d.ts From 812ef89c6949bfa4d88a52764bbff3cfd27999bb Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Tue, 16 Feb 2021 12:05:01 +0100 Subject: [PATCH 3/7] fix serialization of defined intervals --- src/plugins/data/common/search/aggs/buckets/histogram.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.ts b/src/plugins/data/common/search/aggs/buckets/histogram.ts index c3290b5cf18db..ee2137bc044aa 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.ts @@ -159,7 +159,7 @@ export const getHistogramBucketAgg = ({ serialize(val, aggConfig) { // store actually used auto interval in serialized agg config to be able to read it from the result data table meta information const autoBounds = aggConfig?.getAutoBounds(); - if (aggConfig && autoBounds) { + if (val === autoInterval && aggConfig && autoBounds) { const usedInterval = calculateHistogramInterval({ values: autoBounds, interval: aggConfig.params.interval, From 22dfa5de2453767dea7edc6a4eea179d4f225c17 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 18 Feb 2021 13:44:48 +0100 Subject: [PATCH 4/7] refactor into new param --- .../search/aggs/buckets/histogram.test.ts | 8 ++- .../common/search/aggs/buckets/histogram.ts | 62 +++++++++---------- .../get_number_histogram_interval.test.ts | 4 +- .../utils/get_number_histogram_interval.ts | 24 +------ 4 files changed, 38 insertions(+), 60 deletions(-) diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts index 515dfed0c6c4c..46291321d4ceb 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts @@ -13,7 +13,6 @@ import { BUCKET_TYPES } from './bucket_agg_types'; import { IBucketHistogramAggConfig, getHistogramBucketAgg, AutoBounds } from './histogram'; import { BucketAggType } from './bucket_agg_type'; import { SerializableState } from 'src/plugins/expressions/common'; -import { isSerializedAutoInterval } from '../utils/get_number_histogram_interval'; describe('Histogram Agg', () => { let aggTypesDependencies: AggTypesDependencies; @@ -102,6 +101,9 @@ describe('Histogram Agg', () => { "schema": Array [ "segment", ], + "used_interval": Array [ + 100, + ], }, "function": "aggHistogram", "type": "function", @@ -241,8 +243,8 @@ describe('Histogram Agg', () => { }); (aggConfigs.aggs[0] as IBucketHistogramAggConfig).setAutoBounds({ min: 0, max: 1000 }); const serializedAgg = aggConfigs.aggs[0].serialize(); - const serializedIntervalParam = (serializedAgg.params as SerializableState).interval; - expect(isSerializedAutoInterval(serializedIntervalParam as string | number)).toBe(true); + const serializedIntervalParam = (serializedAgg.params as SerializableState).used_interval; + expect(serializedIntervalParam).toBe(500); const freshHistogramAggConfig = getAggConfigs({ interval: 100, field: { diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.ts b/src/plugins/data/common/search/aggs/buckets/histogram.ts index ee2137bc044aa..80f39638ca55f 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.ts @@ -8,6 +8,7 @@ import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { IUiSettingsClient } from 'kibana/public'; import { KBN_FIELD_TYPES, UI_SETTINGS } from '../../../../common'; import { AggTypesDependencies } from '../agg_types'; @@ -20,10 +21,6 @@ import { aggHistogramFnName } from './histogram_fn'; import { ExtendedBounds } from './lib/extended_bounds'; import { isAutoInterval, autoInterval } from './_interval_options'; import { calculateHistogramInterval } from './lib/histogram_calculate_interval'; -import { - buildSerializedAutoInterval, - isSerializedAutoInterval, -} from '../utils/get_number_histogram_interval'; export interface AutoBounds { min: number; @@ -43,6 +40,7 @@ export interface IBucketHistogramAggConfig extends IBucketAggConfig { export interface AggParamsHistogram extends BaseAggParams { field: string; interval: number | string; + used_interval?: number | string; maxBars?: number; intervalBase?: number; min_doc_count?: boolean; @@ -145,39 +143,20 @@ export const getHistogramBucketAgg = ({ }); }, write(aggConfig, output) { - const values = aggConfig.getAutoBounds(); - - output.params.interval = calculateHistogramInterval({ - values, - interval: aggConfig.params.interval, - maxBucketsUiSettings: getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), - maxBucketsUserInput: aggConfig.params.maxBars, - intervalBase: aggConfig.params.intervalBase, - esTypes: aggConfig.params.field?.spec?.esTypes || [], - }); + output.params.interval = calculateInterval(aggConfig, getConfig); }, + }, + { + name: 'used_interval', + default: autoInterval, + shouldShow() { + return false; + }, + write: () => {}, serialize(val, aggConfig) { + if (!aggConfig) return undefined; // store actually used auto interval in serialized agg config to be able to read it from the result data table meta information - const autoBounds = aggConfig?.getAutoBounds(); - if (val === autoInterval && aggConfig && autoBounds) { - const usedInterval = calculateHistogramInterval({ - values: autoBounds, - interval: aggConfig.params.interval, - maxBucketsUiSettings: getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), - maxBucketsUserInput: aggConfig.params.maxBars, - intervalBase: aggConfig.params.intervalBase, - esTypes: aggConfig.params.field?.spec?.esTypes || [], - }); - return buildSerializedAutoInterval(usedInterval); - } else { - return val; - } - }, - deserialize(val) { - if (isSerializedAutoInterval(val)) { - return autoInterval; - } - return val; + return calculateInterval(aggConfig, getConfig); }, }, { @@ -220,3 +199,18 @@ export const getHistogramBucketAgg = ({ }, ], }); + +function calculateInterval( + aggConfig: IBucketHistogramAggConfig, + getConfig: IUiSettingsClient['get'] +): any { + const values = aggConfig.getAutoBounds(); + return calculateHistogramInterval({ + values, + interval: aggConfig.params.interval, + maxBucketsUiSettings: getConfig(UI_SETTINGS.HISTOGRAM_MAX_BARS), + maxBucketsUserInput: aggConfig.params.maxBars, + intervalBase: aggConfig.params.intervalBase, + esTypes: aggConfig.params.field?.spec?.esTypes || [], + }); +} diff --git a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts index afa7cf2ef2dc2..9b08426b551aa 100644 --- a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts +++ b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.test.ts @@ -50,7 +50,8 @@ describe('getNumberHistogramIntervalByDatatableColumn', () => { sourceParams: { type: BUCKET_TYPES.HISTOGRAM, params: { - interval: 'auto$$$20', + interval: 'auto', + used_interval: 20, }, }, }, @@ -70,6 +71,7 @@ describe('getNumberHistogramIntervalByDatatableColumn', () => { type: BUCKET_TYPES.HISTOGRAM, params: { interval: 7, + used_interval: 7, }, }, }, diff --git a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts index 4e753ebaa2cd4..e1c0cf2d69c60 100644 --- a/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts +++ b/src/plugins/data/common/search/aggs/utils/get_number_histogram_interval.ts @@ -10,26 +10,6 @@ import { DatatableColumn } from 'src/plugins/expressions/common'; import type { AggParamsHistogram } from '../buckets'; import { BUCKET_TYPES } from '../buckets/bucket_agg_types'; -const SEPARATOR = '$$$'; - -function parseSerializedInterval(interval: string | number) { - if (typeof interval === 'number') { - return interval; - } - if (interval === 'auto') { - return 'auto'; - } - return Number(interval.split(SEPARATOR)[1]); -} - -export function buildSerializedAutoInterval(usedInterval: number) { - return `auto${SEPARATOR}${usedInterval}`; -} - -export function isSerializedAutoInterval(interval: string | number) { - return typeof interval === 'string' && interval.startsWith('auto'); -} - /** * Helper function returning the used interval for data table column created by the histogramm agg type. * "auto" will get expanded to the actually used interval. @@ -41,8 +21,8 @@ export const getNumberHistogramIntervalByDatatableColumn = (column: DatatableCol if (column.meta.sourceParams?.type !== BUCKET_TYPES.HISTOGRAM) return; const params = (column.meta.sourceParams.params as unknown) as AggParamsHistogram; - if (!params.interval) { + if (!params.used_interval || typeof params.used_interval === 'string') { return undefined; } - return parseSerializedInterval(params.interval); + return params.used_interval; }; From 32250aa7866e7fe090522a883546c360297742b4 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 18 Feb 2021 13:48:08 +0100 Subject: [PATCH 5/7] fix docs --- ...ibana-plugin-plugins-data-public.search.md | 2 +- src/plugins/data/public/public.api.md | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md index 53e58528a6a4f..440fd25993d64 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.search.md @@ -46,7 +46,7 @@ search: { boundLabel: string; intervalLabel: string; })[]; - getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | "auto" | undefined; + getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | undefined; }; getRequestInspectorStats: typeof getRequestInspectorStats; getResponseInspectorStats: typeof getResponseInspectorStats; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 4094927e7f64e..923e76c9adf54 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -2238,7 +2238,7 @@ export const search: { boundLabel: string; intervalLabel: string; })[]; - getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | "auto" | undefined; + getNumberHistogramIntervalByDatatableColumn: (column: import("../../expressions").DatatableColumn) => number | undefined; }; getRequestInspectorStats: typeof getRequestInspectorStats; getResponseInspectorStats: typeof getResponseInspectorStats; @@ -2648,21 +2648,21 @@ export const UI_SETTINGS: { // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:234:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:417:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:418:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:421:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:422:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:425:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:399:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:402:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:411:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:418:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:419:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:422:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:423:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:426:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/search/session/session_service.ts:42:5 - (ae-forgotten-export) The symbol "UrlGeneratorStateMapping" needs to be exported by the entry point index.d.ts From dd5025a065878f45f5ffa439a2b49dd29bd34c5c Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 18 Feb 2021 14:38:39 +0100 Subject: [PATCH 6/7] fix ast building --- src/plugins/data/common/search/aggs/buckets/histogram.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.ts b/src/plugins/data/common/search/aggs/buckets/histogram.ts index 80f39638ca55f..e04ebfe494ba9 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.ts @@ -158,6 +158,7 @@ export const getHistogramBucketAgg = ({ // store actually used auto interval in serialized agg config to be able to read it from the result data table meta information return calculateInterval(aggConfig, getConfig); }, + toExpressionAst: () => undefined, }, { name: 'maxBars', From 35ebddcef3bc554fe1d33c6971d9735c3173dc8f Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Thu, 18 Feb 2021 15:58:31 +0100 Subject: [PATCH 7/7] fix tests --- src/plugins/data/common/search/aggs/buckets/histogram.test.ts | 3 --- .../plugins/lens/public/xy_visualization/expression.test.tsx | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts index 46291321d4ceb..23693eaf5fca5 100644 --- a/src/plugins/data/common/search/aggs/buckets/histogram.test.ts +++ b/src/plugins/data/common/search/aggs/buckets/histogram.test.ts @@ -101,9 +101,6 @@ describe('Histogram Agg', () => { "schema": Array [ "segment", ], - "used_interval": Array [ - 100, - ], }, "function": "aggHistogram", "type": "function", diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx index 305ebf74eea42..279616c56e6d0 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.test.tsx @@ -1913,7 +1913,8 @@ describe('xy_expression', () => { sourceParams: { type: 'histogram', params: { - interval: 'auto$$$5', + interval: 'auto', + used_interval: 5, }, }, };