From 6559bf40711f98e8868fefed03ad1e7acf2feb91 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 28 Jul 2021 17:12:33 +0200 Subject: [PATCH] [FieldFormatters] Remove aggs format decorator from `fieldFormats.deserialize()` (#106755) --- ...plugin-plugins-data-public.customfilter.md | 2 +- ...na-plugin-plugins-data-public.esfilters.md | 2 +- ...bana-plugin-plugins-data-public.eskuery.md | 2 +- ...bana-plugin-plugins-data-public.esquery.md | 2 +- ...lugin-plugins-data-public.esqueryconfig.md | 2 +- ...plugin-plugins-data-public.existsfilter.md | 2 +- ...-plugins-data-public.fieldformat.hidden.md | 15 ++ ...-plugin-plugins-data-public.fieldformat.md | 1 + ...ibana-plugin-plugins-data-public.filter.md | 2 +- ...lugin-plugins-data-public.ifieldsubtype.md | 2 +- ...ana-plugin-plugins-data-public.isfilter.md | 2 +- ...na-plugin-plugins-data-public.isfilters.md | 2 +- ...na-plugin-plugins-data-public.kuerynode.md | 2 +- ...ugin-plugins-data-public.matchallfilter.md | 2 +- ...plugin-plugins-data-public.phrasefilter.md | 2 +- ...lugin-plugins-data-public.phrasesfilter.md | 2 +- ...-plugin-plugins-data-public.rangefilter.md | 2 +- ...gin-plugins-data-public.rangefiltermeta.md | 2 +- ...n-plugins-data-public.rangefilterparams.md | 2 +- .../data/common/field_formats/field_format.ts | 12 ++ .../field_formats/field_formats_registry.ts | 8 +- .../data/common/field_formats/types.ts | 1 + ..._aggs.test.ts => get_aggs_formats.test.ts} | 49 +++---- .../search/aggs/utils/get_aggs_formats.ts | 131 ++++++++++++++++++ .../search/aggs/utils/get_format_with_aggs.ts | 131 ------------------ .../data/common/search/aggs/utils/index.ts | 2 +- .../field_formats_registry.stub.ts | 7 +- .../field_formats/field_formats_service.ts | 5 - .../public/field_formats/utils/deserialize.ts | 48 ------- src/plugins/data/public/plugin.ts | 11 +- src/plugins/data/public/public.api.md | 4 +- 31 files changed, 219 insertions(+), 240 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.hidden.md rename src/plugins/data/common/search/aggs/utils/{get_format_with_aggs.test.ts => get_aggs_formats.test.ts} (75%) create mode 100644 src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts delete mode 100644 src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts delete mode 100644 src/plugins/data/public/field_formats/utils/deserialize.ts diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.customfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.customfilter.md index 6763a8d2ba0bf4..5c666c7f9fe1e1 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.customfilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.customfilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md index 2976c0884fc4cb..ee04b37bb153cb 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import helpers from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import helpers from the package kbn/es-query directly. This import will be removed in v8.0.0. > Filter helpers namespace: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.eskuery.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.eskuery.md index 6ed9898ddd7187..48cb20e0b90326 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.eskuery.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.eskuery.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import helpers from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import helpers from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esquery.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esquery.md index fa2ee4faa74665..deb50b19280107 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esquery.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esquery.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import helpers from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import helpers from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esqueryconfig.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esqueryconfig.md index 4480329c2df192..3e8c3709412607 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esqueryconfig.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esqueryconfig.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.existsfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.existsfilter.md index ab756295eac8c3..ec5bc71c614ecf 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.existsfilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.existsfilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.hidden.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.hidden.md new file mode 100644 index 00000000000000..2032f0fc01112f --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.hidden.md @@ -0,0 +1,15 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) > [hidden](./kibana-plugin-plugins-data-public.fieldformat.hidden.md) + +## FieldFormat.hidden property + +Hidden field formats can only be accessed directly by id, They won't appear in field format editor UI, But they can be accessed and used from code internally. + + {boolean} - Is this a hidden field format + +Signature: + +```typescript +static hidden: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md index c956ffffd85ec7..640064af4be126 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.fieldformat.md @@ -25,6 +25,7 @@ export declare abstract class FieldFormat | [convertObject](./kibana-plugin-plugins-data-public.fieldformat.convertobject.md) | | FieldFormatConvert | undefined | {FieldFormatConvert} have to remove the private because of https://github.com/Microsoft/TypeScript/issues/17293 | | [fieldType](./kibana-plugin-plugins-data-public.fieldformat.fieldtype.md) | static | string | string[] | {string} - Field Format Type | | [getConfig](./kibana-plugin-plugins-data-public.fieldformat.getconfig.md) | | FieldFormatsGetConfigFn | undefined | | +| [hidden](./kibana-plugin-plugins-data-public.fieldformat.hidden.md) | static | boolean | Hidden field formats can only be accessed directly by id, They won't appear in field format editor UI, But they can be accessed and used from code internally. {boolean} - Is this a hidden field format | | [htmlConvert](./kibana-plugin-plugins-data-public.fieldformat.htmlconvert.md) | | HtmlContextTypeConvert | undefined | {htmlConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 | | [id](./kibana-plugin-plugins-data-public.fieldformat.id.md) | static | string | {string} - Field Format Id | | [textConvert](./kibana-plugin-plugins-data-public.fieldformat.textconvert.md) | | TextContextTypeConvert | undefined | {textConvert} have to remove the protected because of https://github.com/Microsoft/TypeScript/issues/17293 | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filter.md index bf8d4ced016a3e..454dde806532f2 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.filter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldsubtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldsubtype.md index d5d8a0b62d3c5b..e2fa06a8acc6c3 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldsubtype.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldsubtype.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md index 2848e20edde1be..eb6b9968544c79 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md index 881d50b8a49e1a..52bfaa67e22588 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kuerynode.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kuerynode.md index 9cea144ff9d46a..bb3eb02dc88b92 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kuerynode.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.kuerynode.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.matchallfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.matchallfilter.md index 39ae82865808c4..36712d80ff6442 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.matchallfilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.matchallfilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasefilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasefilter.md index ca38ac25dcf507..1c0dcc0589d0aa 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasefilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasefilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasesfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasesfilter.md index 0c293cb909276b..64bce6d4f61113 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasesfilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.phrasesfilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilter.md index 3d9af100a707a8..9f072aae6e1948 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilter.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilter.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefiltermeta.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefiltermeta.md index 4060a71e62cd0a..e1b4f2886a6dea 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefiltermeta.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefiltermeta.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilterparams.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilterparams.md index cdf237ea5a1ec0..23c11b1317c7e3 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilterparams.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.rangefilterparams.md @@ -6,7 +6,7 @@ > Warning: This API is now obsolete. > -> Please import from the package kbn/es-query directly. This import will be deprecated in v8.0.0. +> Please import from the package kbn/es-query directly. This import will be removed in v8.0.0. > Signature: diff --git a/src/plugins/data/common/field_formats/field_format.ts b/src/plugins/data/common/field_formats/field_format.ts index e7a4ac2ae63ad5..97b8acd7c019d8 100644 --- a/src/plugins/data/common/field_formats/field_format.ts +++ b/src/plugins/data/common/field_formats/field_format.ts @@ -30,6 +30,18 @@ export abstract class FieldFormat { * @public */ static id: string; + + /** + * Hidden field formats can only be accessed directly by id, + * They won't appear in field format editor UI, + * But they can be accessed and used from code internally. + * + * @property {boolean} - Is this a hidden field format + * @static + * @public + */ + static hidden: boolean; + /** * @property {string} - Field Format Title * @static diff --git a/src/plugins/data/common/field_formats/field_formats_registry.ts b/src/plugins/data/common/field_formats/field_formats_registry.ts index 58660f58569231..996cf05a9faa94 100644 --- a/src/plugins/data/common/field_formats/field_formats_registry.ts +++ b/src/plugins/data/common/field_formats/field_formats_registry.ts @@ -30,7 +30,7 @@ export class FieldFormatsRegistry { protected defaultMap: Record = {}; protected metaParamsOptions: Record = {}; protected getConfig?: FieldFormatsGetConfigFn; - // overriden on the public contract + public deserialize: FormatFactory = (mapping?: SerializedFieldFormat) => { if (!mapping) { return new (FieldFormat.from(identity))(); @@ -215,7 +215,8 @@ export class FieldFormatsRegistry { } /** - * Get filtered list of field formats by format type + * Get filtered list of field formats by format type, + * Skips hidden field formats * * @param {KBN_FIELD_TYPES} fieldType * @return {FieldFormatInstanceType[]} @@ -223,7 +224,8 @@ export class FieldFormatsRegistry { getByFieldType(fieldType: KBN_FIELD_TYPES): FieldFormatInstanceType[] { return [...this.fieldFormats.values()] .filter( - (format: FieldFormatInstanceType) => format && format.fieldType.indexOf(fieldType) !== -1 + (format: FieldFormatInstanceType) => + format && !format.hidden && format.fieldType.indexOf(fieldType) !== -1 ) .map( (format: FieldFormatInstanceType) => diff --git a/src/plugins/data/common/field_formats/types.ts b/src/plugins/data/common/field_formats/types.ts index b1d290388a42b2..c09106751815f3 100644 --- a/src/plugins/data/common/field_formats/types.ts +++ b/src/plugins/data/common/field_formats/types.ts @@ -82,6 +82,7 @@ export type FieldFormatInstanceType = (new ( // Static properties: id: FieldFormatId; title: string; + hidden?: boolean; fieldType: string | string[]; }; diff --git a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.test.ts similarity index 75% rename from src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts rename to src/plugins/data/common/search/aggs/utils/get_aggs_formats.test.ts index 2e502c3b0133f7..1cf80a6d0085c5 100644 --- a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.test.ts +++ b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.test.ts @@ -10,10 +10,20 @@ import { identity } from 'lodash'; import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; import { FieldFormat, IFieldFormat } from '../../../../common'; +import { getAggsFormats } from './get_aggs_formats'; -import { getFormatWithAggs } from './get_format_with_aggs'; +const getAggFormat = ( + mapping: SerializedFieldFormat, + getFormat: (mapping: SerializedFieldFormat) => IFieldFormat +) => { + const aggsFormats = getAggsFormats(getFormat); + const AggFormat = aggsFormats.find((format) => format.id === mapping.id); + if (!AggFormat) throw new Error(`No agg format with id: ${mapping.id}`); -describe('getFormatWithAggs', () => { + return new AggFormat(mapping.params); +}; + +describe('getAggsFormats', () => { let getFormat: jest.MockedFunction<(mapping: SerializedFieldFormat) => IFieldFormat>; beforeEach(() => { @@ -23,19 +33,9 @@ describe('getFormatWithAggs', () => { }); }); - test('calls provided getFormat if no matching aggs exist', () => { - const mapping = { id: 'foo', params: {} }; - const getFieldFormat = getFormatWithAggs(getFormat); - getFieldFormat(mapping); - - expect(getFormat).toHaveBeenCalledTimes(1); - expect(getFormat).toHaveBeenCalledWith(mapping); - }); - test('creates custom format for date_range', () => { const mapping = { id: 'date_range', params: {} }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ from: '2020-05-01', to: '2020-06-01' })).toBe( '2020-05-01 to 2020-06-01' @@ -47,8 +47,7 @@ describe('getFormatWithAggs', () => { test('creates custom format for ip_range', () => { const mapping = { id: 'ip_range', params: {} }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ type: 'range', from: '10.0.0.1', to: '10.0.0.10' })).toBe( '10.0.0.1 to 10.0.0.10' @@ -61,8 +60,7 @@ describe('getFormatWithAggs', () => { test('creates custom format for range', () => { const mapping = { id: 'range', params: {} }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ gte: 1, lt: 20 })).toBe('≥ 1 and < 20'); expect(getFormat).toHaveBeenCalledTimes(1); @@ -70,8 +68,7 @@ describe('getFormatWithAggs', () => { test('creates alternative format for range using the template parameter', () => { const mapping = { id: 'range', params: { template: 'arrow_right' } }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ gte: 1, lt: 20 })).toBe('1 → 20'); expect(getFormat).toHaveBeenCalledTimes(1); @@ -79,8 +76,7 @@ describe('getFormatWithAggs', () => { test('handles Infinity values internally when no nestedFormatter is passed', () => { const mapping = { id: 'range', params: { replaceInfinity: true } }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ gte: -Infinity, lt: Infinity })).toBe('≥ −∞ and < +∞'); expect(getFormat).toHaveBeenCalledTimes(1); @@ -88,8 +84,7 @@ describe('getFormatWithAggs', () => { test('lets Infinity values handling to nestedFormatter even when flag is on', () => { const mapping = { id: 'range', params: { replaceInfinity: true, id: 'any' } }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + const format = getAggFormat(mapping, getFormat); expect(format.convert({ gte: -Infinity, lt: Infinity })).toBe('≥ -Infinity and < Infinity'); expect(getFormat).toHaveBeenCalledTimes(1); @@ -97,8 +92,8 @@ describe('getFormatWithAggs', () => { test('returns custom label for range if provided', () => { const mapping = { id: 'range', params: {} }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + + const format = getAggFormat(mapping, getFormat); expect(format.convert({ gte: 1, lt: 20, label: 'custom' })).toBe('custom'); // underlying formatter is not called because custom label can be used directly @@ -113,8 +108,8 @@ describe('getFormatWithAggs', () => { missingBucketLabel: 'missing bucket', }, }; - const getFieldFormat = getFormatWithAggs(getFormat); - const format = getFieldFormat(mapping); + + const format = getAggFormat(mapping, getFormat); expect(format.convert('machine.os.keyword')).toBe('machine.os.keyword'); expect(format.convert('__other__')).toBe(mapping.params.otherBucketLabel); diff --git a/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts new file mode 100644 index 00000000000000..b1c9dae69bf4e0 --- /dev/null +++ b/src/plugins/data/common/search/aggs/utils/get_aggs_formats.ts @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/* eslint-disable max-classes-per-file */ +import { i18n } from '@kbn/i18n'; + +import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; +import { + FieldFormat, + FieldFormatInstanceType, + FieldFormatsContentType, + IFieldFormat, +} from '../../../../common/field_formats'; +import { convertDateRangeToString, DateRangeKey } from '../buckets/lib/date_range'; +import { convertIPRangeToString, IpRangeKey } from '../buckets/lib/ip_range'; + +type GetFieldFormat = (mapping: SerializedFieldFormat) => IFieldFormat; + +/** + * Certain aggs have custom field formats that have dependency on aggs code. + * This function creates such field formats types and then those are added to field formatters registry + * + * These formats can't be used from field format editor UI + * + * This function is internal to the data plugin, and only exists for use inside + * the field formats service. + * + * @internal + */ +export function getAggsFormats(getFieldFormat: GetFieldFormat): FieldFormatInstanceType[] { + return [ + class AggsRangeFieldFormat extends FieldFormat { + static id = 'range'; + static hidden = true; + + textConvert = (range: any) => { + const params = this._params; + + if (range.label) { + return range.label; + } + const nestedFormatter = params as SerializedFieldFormat; + const format = getFieldFormat({ + id: nestedFormatter.id, + params: nestedFormatter.params, + }); + + const gte = '\u2265'; + const lt = '\u003c'; + let fromValue = format.convert(range.gte); + let toValue = format.convert(range.lt); + // In case of identity formatter and a specific flag, replace Infinity values by specific strings + if (params.replaceInfinity && nestedFormatter.id == null) { + const FROM_PLACEHOLDER = '\u2212\u221E'; + const TO_PLACEHOLDER = '+\u221E'; + fromValue = isFinite(range.gte) ? fromValue : FROM_PLACEHOLDER; + toValue = isFinite(range.lt) ? toValue : TO_PLACEHOLDER; + } + + if (params.template === 'arrow_right') { + return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessageArrowRight', { + defaultMessage: '{from} → {to}', + values: { + from: fromValue, + to: toValue, + }, + }); + } + return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessage', { + defaultMessage: '{gte} {from} and {lt} {to}', + values: { + gte, + from: fromValue, + lt, + to: toValue, + }, + }); + }; + }, + class AggsDateRangeFieldFormat extends FieldFormat { + static id = 'date_range'; + static hidden = true; + + textConvert = (range: DateRangeKey) => { + const nestedFormatter = this._params as SerializedFieldFormat; + const format = getFieldFormat({ + id: nestedFormatter.id, + params: nestedFormatter.params, + }); + return convertDateRangeToString(range, format.convert.bind(format)); + }; + }, + class AggsIpRangeFieldFormat extends FieldFormat { + static id = 'ip_range'; + static hidden = true; + + textConvert = (range: IpRangeKey) => { + const nestedFormatter = this._params as SerializedFieldFormat; + const format = getFieldFormat({ + id: nestedFormatter.id, + params: nestedFormatter.params, + }); + return convertIPRangeToString(range, format.convert.bind(format)); + }; + }, + class AggsTermsFieldFormat extends FieldFormat { + static id = 'terms'; + static hidden = true; + + convert = (val: string, type: FieldFormatsContentType) => { + const params = this._params; + const format = getFieldFormat({ id: params.id, params }); + + if (val === '__other__') { + return params.otherBucketLabel; + } + if (val === '__missing__') { + return params.missingBucketLabel; + } + + return format.convert(val, type); + }; + getConverterFor = (type: FieldFormatsContentType) => (val: string) => this.convert(val, type); + }, + ]; +} diff --git a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts b/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts deleted file mode 100644 index 210e2d23147488..00000000000000 --- a/src/plugins/data/common/search/aggs/utils/get_format_with_aggs.ts +++ /dev/null @@ -1,131 +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 { i18n } from '@kbn/i18n'; - -import { SerializedFieldFormat } from 'src/plugins/expressions/common/types'; -import { - FieldFormat, - FieldFormatsContentType, - IFieldFormat, -} from '../../../../common/field_formats'; -import { convertDateRangeToString, DateRangeKey } from '../buckets/lib/date_range'; -import { convertIPRangeToString, IpRangeKey } from '../buckets/lib/ip_range'; - -type GetFieldFormat = (mapping: SerializedFieldFormat) => IFieldFormat; - -/** - * Certain aggs have custom field formats that are not part of the field formats - * registry. This function will take the `getFormat` function which is used inside - * `deserializeFieldFormat` and decorate it with the additional custom formats - * that the field formats service doesn't know anything about. - * - * This function is internal to the data plugin, and only exists for use inside - * the field formats service. - * - * @internal - */ -export function getFormatWithAggs(getFieldFormat: GetFieldFormat): GetFieldFormat { - return (mapping) => { - const { id, params = {} } = mapping; - - const customFormats: Record IFieldFormat> = { - range: () => { - const RangeFormat = FieldFormat.from((range: any) => { - if (range.label) { - return range.label; - } - const nestedFormatter = params as SerializedFieldFormat; - const format = getFieldFormat({ - id: nestedFormatter.id, - params: nestedFormatter.params, - }); - - const gte = '\u2265'; - const lt = '\u003c'; - let fromValue = format.convert(range.gte); - let toValue = format.convert(range.lt); - // In case of identity formatter and a specific flag, replace Infinity values by specific strings - if (params.replaceInfinity && nestedFormatter.id == null) { - const FROM_PLACEHOLDER = '\u2212\u221E'; - const TO_PLACEHOLDER = '+\u221E'; - fromValue = isFinite(range.gte) ? fromValue : FROM_PLACEHOLDER; - toValue = isFinite(range.lt) ? toValue : TO_PLACEHOLDER; - } - - if (params.template === 'arrow_right') { - return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessageArrowRight', { - defaultMessage: '{from} → {to}', - values: { - from: fromValue, - to: toValue, - }, - }); - } - return i18n.translate('data.aggTypes.buckets.ranges.rangesFormatMessage', { - defaultMessage: '{gte} {from} and {lt} {to}', - values: { - gte, - from: fromValue, - lt, - to: toValue, - }, - }); - }); - return new RangeFormat(); - }, - date_range: () => { - const nestedFormatter = params as SerializedFieldFormat; - const DateRangeFormat = FieldFormat.from((range: DateRangeKey) => { - const format = getFieldFormat({ - id: nestedFormatter.id, - params: nestedFormatter.params, - }); - return convertDateRangeToString(range, format.convert.bind(format)); - }); - return new DateRangeFormat(); - }, - ip_range: () => { - const nestedFormatter = params as SerializedFieldFormat; - const IpRangeFormat = FieldFormat.from((range: IpRangeKey) => { - const format = getFieldFormat({ - id: nestedFormatter.id, - params: nestedFormatter.params, - }); - return convertIPRangeToString(range, format.convert.bind(format)); - }); - return new IpRangeFormat(); - }, - terms: () => { - const convert = (val: string, type: FieldFormatsContentType) => { - const format = getFieldFormat({ id: params.id, params }); - - if (val === '__other__') { - return params.otherBucketLabel; - } - if (val === '__missing__') { - return params.missingBucketLabel; - } - - return format.convert(val, type); - }; - - return { - convert, - getConverterFor: (type: FieldFormatsContentType) => (val: string) => convert(val, type), - } as IFieldFormat; - }, - }; - - if (!id || !(id in customFormats)) { - return getFieldFormat(mapping); - } - - return customFormats[id](); - }; -} diff --git a/src/plugins/data/common/search/aggs/utils/index.ts b/src/plugins/data/common/search/aggs/utils/index.ts index 2bfdc47d31202e..2edce79ca690b7 100644 --- a/src/plugins/data/common/search/aggs/utils/index.ts +++ b/src/plugins/data/common/search/aggs/utils/index.ts @@ -10,7 +10,7 @@ export * from './calculate_auto_time_expression'; export { getNumberHistogramIntervalByDatatableColumn } from './get_number_histogram_interval'; export { getDateHistogramMetaDataByDatatableColumn } from './get_date_histogram_meta'; export * from './date_interval_utils'; -export * from './get_format_with_aggs'; +export * from './get_aggs_formats'; export * from './ip_address'; export * from './prop_filter'; export * from './to_angular_json'; diff --git a/src/plugins/data/public/field_formats/field_formats_registry.stub.ts b/src/plugins/data/public/field_formats/field_formats_registry.stub.ts index 77ef621721c3a9..566532085059d2 100644 --- a/src/plugins/data/public/field_formats/field_formats_registry.stub.ts +++ b/src/plugins/data/public/field_formats/field_formats_registry.stub.ts @@ -7,9 +7,8 @@ */ import { CoreSetup } from 'src/core/public'; -import { deserializeFieldFormat } from './utils/deserialize'; import { baseFormattersPublic } from './constants'; -import { DataPublicPluginStart, fieldFormats } from '..'; +import { fieldFormats } from '..'; export const getFieldFormatsRegistry = (core: CoreSetup) => { const fieldFormatsRegistry = new fieldFormats.FieldFormatsRegistry(); @@ -17,9 +16,5 @@ export const getFieldFormatsRegistry = (core: CoreSetup) => { fieldFormatsRegistry.init(getConfig, {}, baseFormattersPublic); - fieldFormatsRegistry.deserialize = deserializeFieldFormat.bind( - fieldFormatsRegistry as DataPublicPluginStart['fieldFormats'] - ); - return fieldFormatsRegistry; }; diff --git a/src/plugins/data/public/field_formats/field_formats_service.ts b/src/plugins/data/public/field_formats/field_formats_service.ts index 89b3bf2249315f..041d0d7dd0e1c8 100644 --- a/src/plugins/data/public/field_formats/field_formats_service.ts +++ b/src/plugins/data/public/field_formats/field_formats_service.ts @@ -8,7 +8,6 @@ import { CoreSetup } from 'src/core/public'; import { FieldFormatsRegistry, UI_SETTINGS } from '../../common'; -import { deserializeFieldFormat } from './utils/deserialize'; import { FormatFactory } from '../../common/field_formats/utils'; import { baseFormattersPublic } from './constants'; @@ -40,10 +39,6 @@ export class FieldFormatsService { } public start() { - this.fieldFormatsRegistry.deserialize = deserializeFieldFormat.bind( - this.fieldFormatsRegistry as FieldFormatsStart - ); - return this.fieldFormatsRegistry as FieldFormatsStart; } } diff --git a/src/plugins/data/public/field_formats/utils/deserialize.ts b/src/plugins/data/public/field_formats/utils/deserialize.ts deleted file mode 100644 index 17134a49d7898c..00000000000000 --- a/src/plugins/data/public/field_formats/utils/deserialize.ts +++ /dev/null @@ -1,48 +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 { identity } from 'lodash'; - -import { SerializedFieldFormat } from '../../../../expressions/common/types'; - -import { FieldFormat } from '../../../common'; -import { FormatFactory } from '../../../common/field_formats/utils'; -import { getFormatWithAggs } from '../../../common/search/aggs'; -import { DataPublicPluginStart, IFieldFormat } from '../../../public'; -import { getUiSettings } from '../../../public/services'; - -const getConfig = (key: string, defaultOverride?: any): any => - getUiSettings().get(key, defaultOverride); -const DefaultFieldFormat = FieldFormat.from(identity); - -export const deserializeFieldFormat: FormatFactory = function ( - this: DataPublicPluginStart['fieldFormats'], - serializedFieldFormat?: SerializedFieldFormat -) { - if (!serializedFieldFormat) { - return new DefaultFieldFormat(); - } - - const getFormat = (mapping: SerializedFieldFormat): IFieldFormat => { - const { id, params = {} } = mapping; - if (id) { - const Format = this.getType(id); - - if (Format) { - return new Format(params, getConfig); - } - } - - return new DefaultFieldFormat(); - }; - - // decorate getFormat to handle custom types created by aggs - const getFieldFormat = getFormatWithAggs(getFormat); - - return getFieldFormat(serializedFieldFormat); -}; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 2da3b900299806..7a071dbffe696a 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -50,6 +50,7 @@ import { getIndexPatternLoad } from './index_patterns/expressions'; import { UsageCollectionSetup } from '../../usage_collection/public'; import { getTableViewDescription } from './utils/table_inspector_view'; import { NowProvider, NowProviderInternalContract } from './now_provider'; +import { getAggsFormats } from '../common'; export class DataPublicPlugin implements @@ -71,6 +72,7 @@ export class DataPublicPlugin this.searchService = new SearchService(initializerContext); this.queryService = new QueryService(); this.fieldFormatsService = new FieldFormatsService(); + this.autocomplete = new AutocompleteService(initializerContext); this.storage = new Storage(window.localStorage); this.nowProvider = new NowProvider(); @@ -113,13 +115,20 @@ export class DataPublicPlugin })) ); + const fieldFormats = this.fieldFormatsService.setup(core); + fieldFormats.register( + getAggsFormats((serializedFieldFormat) => + startServices().self.fieldFormats.deserialize(serializedFieldFormat) + ) + ); + return { autocomplete: this.autocomplete.setup(core, { timefilter: queryService.timefilter, usageCollection, }), search: searchService, - fieldFormats: this.fieldFormatsService.setup(core), + fieldFormats, query: queryService, }; } diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index bc90bb2a2e15c1..c31057b79f2498 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -988,6 +988,7 @@ export abstract class FieldFormat { // Warning: (ae-forgotten-export) The symbol "FieldFormatConvertFunction" needs to be exported by the entry point index.d.ts getConverterFor(contentType?: FieldFormatsContentType): FieldFormatConvertFunction; getParamDefaults(): Record; + static hidden: boolean; // Warning: (ae-forgotten-export) The symbol "HtmlContextTypeConvert" needs to be exported by the entry point index.d.ts htmlConvert: HtmlContextTypeConvert | undefined; static id: string; @@ -1031,6 +1032,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string; export type FieldFormatInstanceType = (new (params?: any, getConfig?: FieldFormatsGetConfigFn) => FieldFormat) & { id: FieldFormatId; title: string; + hidden?: boolean; fieldType: string | string[]; }; @@ -2728,7 +2730,7 @@ export interface WaitUntilNextSessionCompletesOptions { // src/plugins/data/public/deprecated.ts:93:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts // src/plugins/data/public/deprecated.ts:93:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts // src/plugins/data/public/deprecated.ts:93:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/field_formats/field_formats_service.ts:56:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/field_formats/field_formats_service.ts:51:3 - (ae-forgotten-export) The symbol "FormatFactory" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:57:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:57:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:57:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts