From 61f97294f6a637e17b90594b9684a7b5b102d16c Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 09:56:20 -0500 Subject: [PATCH 01/62] init --- .../classes/fields/es_agg_factory.test.ts | 28 +++++++ .../public/classes/fields/es_agg_factory.ts | 49 ++++++++++++ .../classes/fields/es_agg_field.test.ts | 22 +----- .../public/classes/fields/es_agg_field.ts | 75 +++++-------------- .../public/classes/fields/es_fielded_agg.ts | 57 ++++++++++++++ .../sources/es_agg_source/es_agg_source.ts | 2 +- 6 files changed, 153 insertions(+), 80 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts create mode 100644 x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts create mode 100644 x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts new file mode 100644 index 0000000000000..07f2dae542d37 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { esAggFieldsFactory } from './es_agg_field'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; + +describe('esAggFieldsFactory', () => { + test('Should only create top terms field when term field is not provided', () => { + const fields = esAggFieldsFactory( + { type: AGG_TYPE.TERMS }, + mockEsAggSource, + FIELD_ORIGIN.SOURCE + ); + expect(fields.length).toBe(1); + }); + + test('Should create top terms and top terms percentage fields', () => { + const fields = esAggFieldsFactory( + { type: AGG_TYPE.TERMS, field: 'myField' }, + mockEsAggSource, + FIELD_ORIGIN.SOURCE + ); + expect(fields.length).toBe(2); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts new file mode 100644 index 0000000000000..95ccd5022e1dc --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AggDescriptor } from '../../../common/descriptor_types'; +import { IESAggSource } from '../sources/es_agg_source'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; +import { ESDocField } from './es_doc_field'; +import { TopTermPercentageField } from './top_term_percentage_field'; +import { ESAggField, IESAggField } from './es_agg_field'; +import { ESFieldedAgg } from './es_fielded_agg'; + +export function esAggFieldsFactory( + aggDescriptor: AggDescriptor, + source: IESAggSource, + origin: FIELD_ORIGIN, + canReadFromGeoJson: boolean = true +): IESAggField[] { + let aggField; + if (aggDescriptor.type === AGG_TYPE.COUNT) { + aggField = new ESAggField({ + label: aggDescriptor.label, + source, + origin, + canReadFromGeoJson, + }); + } else { + aggField = new ESFieldedAgg({ + label: aggDescriptor.label, + esDocField: aggDescriptor.field + ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) + : undefined, + aggType: aggDescriptor.type, + source, + origin, + canReadFromGeoJson, + }); + } + + const aggFields: IESAggField[] = [aggField]; + + if (aggDescriptor.field && aggDescriptor.type === AGG_TYPE.TERMS) { + aggFields.push(new TopTermPercentageField(aggField, canReadFromGeoJson)); + } + + return aggFields; +} diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts index 7a65b5f9f6b46..405791ad816d9 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESAggField, esAggFieldsFactory } from './es_agg_field'; +import { ESAggField } from './es_agg_field'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { IESAggSource } from '../sources/es_agg_source'; import { IIndexPattern } from 'src/plugins/data/public'; @@ -58,23 +58,3 @@ describe('supportsFieldMeta', () => { expect(uniqueCountMetric.supportsFieldMeta()).toBe(false); }); }); - -describe('esAggFieldsFactory', () => { - test('Should only create top terms field when term field is not provided', () => { - const fields = esAggFieldsFactory( - { type: AGG_TYPE.TERMS }, - mockEsAggSource, - FIELD_ORIGIN.SOURCE - ); - expect(fields.length).toBe(1); - }); - - test('Should create top terms and top terms percentage fields', () => { - const fields = esAggFieldsFactory( - { type: AGG_TYPE.TERMS, field: 'myField' }, - mockEsAggSource, - FIELD_ORIGIN.SOURCE - ); - expect(fields.length).toBe(2); - }); -}); diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts index 8cff98205186f..4f2be1a023b46 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts @@ -6,14 +6,10 @@ import { IndexPattern } from 'src/plugins/data/public'; import { IField } from './field'; -import { AggDescriptor } from '../../../common/descriptor_types'; import { IESAggSource } from '../sources/es_agg_source'; import { IVectorSource } from '../sources/vector_source'; -import { ESDocField } from './es_doc_field'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { isMetricCountable } from '../util/is_metric_countable'; -import { getField, addFieldToDSL } from '../../../common/elasticsearch_util'; -import { TopTermPercentageField } from './top_term_percentage_field'; +import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; import { ESAggTooltipProperty } from '../tooltips/es_agg_tooltip_property'; @@ -24,34 +20,24 @@ export interface IESAggField extends IField { getBucketCount(): number; } +export interface IESAggFieldParams { + label?: string; + source: IESAggSource; + origin: FIELD_ORIGIN; + canReadFromGeoJson?: boolean; +} + +// Agg without field. Essentially a count-aggregation. export class ESAggField implements IESAggField { private readonly _source: IESAggSource; private readonly _origin: FIELD_ORIGIN; private readonly _label?: string; - private readonly _aggType: AGG_TYPE; - private readonly _esDocField?: IField | undefined; private readonly _canReadFromGeoJson: boolean; - constructor({ - label, - source, - aggType, - esDocField, - origin, - canReadFromGeoJson = true, - }: { - label?: string; - source: IESAggSource; - aggType: AGG_TYPE; - esDocField?: IField; - origin: FIELD_ORIGIN; - canReadFromGeoJson?: boolean; - }) { + constructor({ label, source, origin, canReadFromGeoJson = true }: IESAggFieldParams) { this._source = source; this._origin = origin; this._label = label; - this._aggType = aggType; - this._esDocField = esDocField; this._canReadFromGeoJson = canReadFromGeoJson; } @@ -78,11 +64,11 @@ export class ESAggField implements IESAggField { } getAggType(): AGG_TYPE { - return this._aggType; + return AGG_TYPE.COUNT; } isValid(): boolean { - return this.getAggType() === AGG_TYPE.COUNT ? true : !!this._esDocField; + return true; } async getDataType(): Promise { @@ -90,7 +76,7 @@ export class ESAggField implements IESAggField { } _getESDocFieldName(): string { - return this._esDocField ? this._esDocField.getName() : ''; + return ''; } async createTooltipProperty(value: string | string[] | undefined): Promise { @@ -119,20 +105,19 @@ export class ESAggField implements IESAggField { supportsFieldMeta(): boolean { // count and sum aggregations are not within field bounds so they do not support field meta. - return !isMetricCountable(this.getAggType()); + return false; } canValueBeFormatted(): boolean { - // Do not use field formatters for counting metrics - return ![AGG_TYPE.COUNT, AGG_TYPE.UNIQUE_COUNT].includes(this.getAggType()); + return false; } async getOrdinalFieldMetaRequest(): Promise { - return this._esDocField ? this._esDocField.getOrdinalFieldMetaRequest() : null; + return null; } async getCategoricalFieldMetaRequest(size: number): Promise { - return this._esDocField ? this._esDocField.getCategoricalFieldMetaRequest(size) : null; + return null; } supportsAutoDomain(): boolean { @@ -143,29 +128,3 @@ export class ESAggField implements IESAggField { return this._canReadFromGeoJson; } } - -export function esAggFieldsFactory( - aggDescriptor: AggDescriptor, - source: IESAggSource, - origin: FIELD_ORIGIN, - canReadFromGeoJson: boolean = true -): IESAggField[] { - const aggField = new ESAggField({ - label: aggDescriptor.label, - esDocField: aggDescriptor.field - ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) - : undefined, - aggType: aggDescriptor.type, - source, - origin, - canReadFromGeoJson, - }); - - const aggFields: IESAggField[] = [aggField]; - - if (aggDescriptor.field && aggDescriptor.type === AGG_TYPE.TERMS) { - aggFields.push(new TopTermPercentageField(aggField, canReadFromGeoJson)); - } - - return aggFields; -} diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts new file mode 100644 index 0000000000000..5ee6661b4a5b4 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IField } from './field'; +import { AGG_TYPE } from '../../../common/constants'; +import { ESAggField } from './es_agg_field'; +import { IESAggFieldParams } from './es_agg_field'; +import { isMetricCountable } from '../util/is_metric_countable'; + +export interface IESFieldedAggParams extends IESAggFieldParams { + esDocField?: IField; + aggType: AGG_TYPE; +} + +export class ESFieldedAgg extends ESAggField { + private readonly _esDocField?: IField; + private readonly _aggType: AGG_TYPE; + + constructor(params: IESFieldedAggParams) { + super(params); + this._esDocField = params.esDocField; + this._aggType = params.aggType; + } + + _getESDocFieldName(): string { + return this._esDocField ? this._esDocField.getName() : ''; + } + + isValid(): boolean { + return !!this._esDocField; + } + + supportsFieldMeta(): boolean { + // count and sum aggregations are not within field bounds so they do not support field meta. + return !isMetricCountable(this.getAggType()); + } + + canValueBeFormatted(): boolean { + // Do not use field formatters for counting metrics + return ![AGG_TYPE.COUNT, AGG_TYPE.UNIQUE_COUNT].includes(this.getAggType()); + } + + getAggType(): AGG_TYPE { + return this._aggType; + } + + async getOrdinalFieldMetaRequest(): Promise { + return this._esDocField ? await this._esDocField.getOrdinalFieldMetaRequest() : null; + } + + async getCategoricalFieldMetaRequest(size: number): Promise { + return this._esDocField ? await this._esDocField.getCategoricalFieldMetaRequest(size) : null; + } +} diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index dc95632032fa9..5d7d7c6f1fbc7 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -9,7 +9,7 @@ import { Adapters } from 'src/plugins/inspector/public'; import { GeoJsonProperties } from 'geojson'; import { IESSource } from '../es_source'; import { AbstractESSource } from '../es_source'; -import { esAggFieldsFactory } from '../../fields/es_agg_field'; +import { esAggFieldsFactory } from '../../fields/es_agg_factory'; import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; import { IESAggField } from '../../fields/es_agg_field'; import { getSourceAggKey } from '../../../../common/get_agg_key'; From 18dac03020a897e488c64f16b4c4e302348d9763 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 10:05:52 -0500 Subject: [PATCH 02/62] Fix tests/rename --- .../classes/fields/es_agg_factory.test.ts | 15 ++++- .../public/classes/fields/es_agg_factory.ts | 4 +- .../classes/fields/es_agg_field.test.ts | 17 +----- .../fields/es_fielded_agg_field.test.ts | 60 +++++++++++++++++++ ...fielded_agg.ts => es_fielded_agg_field.ts} | 2 +- 5 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts rename x-pack/plugins/maps/public/classes/fields/{es_fielded_agg.ts => es_fielded_agg_field.ts} (97%) diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts index 07f2dae542d37..48542ea69783d 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts @@ -4,8 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { esAggFieldsFactory } from './es_agg_field'; +import { esAggFieldsFactory } from './es_agg_factory'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; +import { IESAggSource } from '../sources/es_agg_source'; + +const mockEsAggSource = { + getAggKey: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_key'; + }, + getAggLabel: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_label'; + }, + getIndexPattern: async () => { + return mockIndexPattern; + }, +} as IESAggSource; describe('esAggFieldsFactory', () => { test('Should only create top terms field when term field is not provided', () => { diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index 95ccd5022e1dc..1a00fcbea0f2c 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -10,7 +10,7 @@ import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { ESDocField } from './es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; import { ESAggField, IESAggField } from './es_agg_field'; -import { ESFieldedAgg } from './es_fielded_agg'; +import { ESFieldedAggField } from './es_fielded_agg'; export function esAggFieldsFactory( aggDescriptor: AggDescriptor, @@ -27,7 +27,7 @@ export function esAggFieldsFactory( canReadFromGeoJson, }); } else { - aggField = new ESFieldedAgg({ + aggField = new ESFieldedAggField({ label: aggDescriptor.label, esDocField: aggDescriptor.field ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts index 405791ad816d9..06ddd1f4311f2 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts @@ -38,23 +38,8 @@ const defaultParams = { }; describe('supportsFieldMeta', () => { - test('Non-counting aggregations should support field meta', () => { - const avgMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.AVG }); - expect(avgMetric.supportsFieldMeta()).toBe(true); - const maxMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.MAX }); - expect(maxMetric.supportsFieldMeta()).toBe(true); - const minMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.MIN }); - expect(minMetric.supportsFieldMeta()).toBe(true); - const termsMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.TERMS }); - expect(termsMetric.supportsFieldMeta()).toBe(true); - }); - test('Counting aggregations should not support field meta', () => { - const countMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.COUNT }); + const countMetric = new ESAggField({ ...defaultParams }); expect(countMetric.supportsFieldMeta()).toBe(false); - const sumMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.SUM }); - expect(sumMetric.supportsFieldMeta()).toBe(false); - const uniqueCountMetric = new ESAggField({ ...defaultParams, aggType: AGG_TYPE.UNIQUE_COUNT }); - expect(uniqueCountMetric.supportsFieldMeta()).toBe(false); }); }); diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts new file mode 100644 index 0000000000000..d4c60941e879e --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ESFieldedAggField } from './es_fielded_agg_field'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; +import { IESAggSource } from '../sources/es_agg_source'; +import { IIndexPattern } from 'src/plugins/data/public'; + +const mockIndexPattern = { + title: 'wildIndex', + fields: [ + { + name: 'foo*', + }, + ], +} as IIndexPattern; + +const mockEsAggSource = { + getAggKey: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_key'; + }, + getAggLabel: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_label'; + }, + getIndexPattern: async () => { + return mockIndexPattern; + }, +} as IESAggSource; + +const defaultParams = { + label: 'my agg field', + source: mockEsAggSource, + origin: FIELD_ORIGIN.SOURCE, +}; + +describe('supportsFieldMeta', () => { + test('Non-counting aggregations should support field meta', () => { + const avgMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.AVG }); + expect(avgMetric.supportsFieldMeta()).toBe(true); + const maxMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.MAX }); + expect(maxMetric.supportsFieldMeta()).toBe(true); + const minMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.MIN }); + expect(minMetric.supportsFieldMeta()).toBe(true); + const termsMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.TERMS }); + expect(termsMetric.supportsFieldMeta()).toBe(true); + }); + + test('Counting aggregations should not support field meta', () => { + const sumMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.SUM }); + expect(sumMetric.supportsFieldMeta()).toBe(false); + const uniqueCountMetric = new ESFieldedAggField({ + ...defaultParams, + aggType: AGG_TYPE.UNIQUE_COUNT, + }); + expect(uniqueCountMetric.supportsFieldMeta()).toBe(false); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts similarity index 97% rename from x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts rename to x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts index 5ee6661b4a5b4..52fcc0d7f99c8 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts @@ -15,7 +15,7 @@ export interface IESFieldedAggParams extends IESAggFieldParams { aggType: AGG_TYPE; } -export class ESFieldedAgg extends ESAggField { +export class ESFieldedAggField extends ESAggField { private readonly _esDocField?: IField; private readonly _aggType: AGG_TYPE; From 934d689b18e83984bc753abb74d6df825d6c09af Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 10:10:36 -0500 Subject: [PATCH 03/62] Type fixes --- .../maps/public/classes/fields/es_agg_factory.test.ts | 10 ++++++++++ .../maps/public/classes/fields/es_agg_factory.ts | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts index 48542ea69783d..b06fc6b959628 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts @@ -7,6 +7,16 @@ import { esAggFieldsFactory } from './es_agg_factory'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { IESAggSource } from '../sources/es_agg_source'; +import { IIndexPattern } from '../../../../../../src/plugins/data/common/index_patterns'; + +const mockIndexPattern = { + title: 'wildIndex', + fields: [ + { + name: 'foo*', + }, + ], +} as IIndexPattern; const mockEsAggSource = { getAggKey: (aggType: AGG_TYPE, fieldName: string) => { diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index 1a00fcbea0f2c..7706cb528d660 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -10,7 +10,7 @@ import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { ESDocField } from './es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; import { ESAggField, IESAggField } from './es_agg_field'; -import { ESFieldedAggField } from './es_fielded_agg'; +import { ESFieldedAggField } from './es_fielded_agg_field'; export function esAggFieldsFactory( aggDescriptor: AggDescriptor, From dca9608cee33103346a4c2fe6c721e6c2784107c Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 11:28:06 -0500 Subject: [PATCH 04/62] adding descriptors --- .../source_descriptor_types.ts | 22 ++++++++++-- .../maps/common/migrations/join_agg_key.ts | 2 +- .../public/classes/fields/es_agg_factory.ts | 9 ++--- .../create_choropleth_layer_descriptor.ts | 6 ++-- .../create_region_map_layer_descriptor.ts | 2 +- .../create_tile_map_layer_descriptor.ts | 2 +- .../maps/public/classes/layers/layer.tsx | 4 +-- .../observability/create_layer_descriptor.ts | 4 +-- .../metrics_editor/metric_editor.tsx | 35 ++++++++++++------- 9 files changed, 56 insertions(+), 30 deletions(-) diff --git a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts index a6afbe4d55f9b..ef48f323a1ad8 100644 --- a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts @@ -40,12 +40,28 @@ export type AbstractESSourceDescriptor = AbstractSourceDescriptor & { applyGlobalTime: boolean; }; -export type AggDescriptor = { - field?: string; // count aggregation does not require field. All other aggregation types do - label?: string; +export type AbstractAggDescriptor = { type: AGG_TYPE; + label?: string; +}; + +export type CountAggDescriptor = AbstractAggDescriptor & { + type: AGG_TYPE.COUNT; }; +export type FieldedAggDescriptor = AbstractAggDescriptor & { + type: + | AGG_TYPE.UNIQUE_COUNT + | AGG_TYPE.MAX + | AGG_TYPE.MIN + | AGG_TYPE.SUM + | AGG_TYPE.AVG + | AGG_TYPE.TERMS; + field?: string; +}; + +export type AggDescriptor = CountAggDescriptor | FieldedAggDescriptor; + export type AbstractESAggSourceDescriptor = AbstractESSourceDescriptor & { metrics: AggDescriptor[]; }; diff --git a/x-pack/plugins/maps/common/migrations/join_agg_key.ts b/x-pack/plugins/maps/common/migrations/join_agg_key.ts index 4dc70d3c0fa22..b961637218dd6 100644 --- a/x-pack/plugins/maps/common/migrations/join_agg_key.ts +++ b/x-pack/plugins/maps/common/migrations/join_agg_key.ts @@ -82,7 +82,7 @@ export function migrateJoinAggKey({ _.get(joinDescriptor, 'right.metrics', []).forEach((aggDescriptor: AggDescriptor) => { const legacyAggKey = getLegacyAggKey({ aggType: aggDescriptor.type, - aggFieldName: aggDescriptor.field, + aggFieldName: 'field' in aggDescriptor ? aggDescriptor.field : undefined, indexPatternTitle: _.get(joinDescriptor, 'right.indexPatternTitle', ''), termFieldName: _.get(joinDescriptor, 'right.term', ''), }); diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index 7706cb528d660..f06433a1f7cf7 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -29,9 +29,10 @@ export function esAggFieldsFactory( } else { aggField = new ESFieldedAggField({ label: aggDescriptor.label, - esDocField: aggDescriptor.field - ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) - : undefined, + esDocField: + 'field' in aggDescriptor && aggDescriptor.field + ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) + : undefined, aggType: aggDescriptor.type, source, origin, @@ -41,7 +42,7 @@ export function esAggFieldsFactory( const aggFields: IESAggField[] = [aggField]; - if (aggDescriptor.field && aggDescriptor.type === AGG_TYPE.TERMS) { + if ('field' in aggDescriptor && aggDescriptor.type === AGG_TYPE.TERMS) { aggFields.push(new TopTermPercentageField(aggField, canReadFromGeoJson)); } diff --git a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts index 43d1d39c170c0..cdfe60946f5f9 100644 --- a/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/choropleth_layer_wizard/create_choropleth_layer_descriptor.ts @@ -16,8 +16,8 @@ import { } from '../../../../common/constants'; import { getJoinAggKey } from '../../../../common/get_agg_key'; import { - AggDescriptor, ColorDynamicOptions, + CountAggDescriptor, EMSFileSourceDescriptor, ESSearchSourceDescriptor, } from '../../../../common/descriptor_types'; @@ -43,11 +43,11 @@ function createChoroplethLayerDescriptor({ rightIndexPatternTitle: string; rightTermField: string; }) { - const metricsDescriptor: AggDescriptor = { type: AGG_TYPE.COUNT }; + const metricsDescriptor: CountAggDescriptor = { type: AGG_TYPE.COUNT }; const joinId = uuid(); const joinKey = getJoinAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + aggFieldName: '', rightSourceId: joinId, }); return VectorLayer.createDescriptor({ diff --git a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts index 8830831b8b656..6f9bb686459b5 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts @@ -69,7 +69,7 @@ export function createRegionMapLayerDescriptor({ const joinId = uuid(); const joinKey = getJoinAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', rightSourceId: joinId, }); const colorPallette = NUMERICAL_COLOR_PALETTES.find((pallette) => { diff --git a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts index 05a8620e436d5..5b89373f2db48 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts @@ -103,7 +103,7 @@ export function createTileMapLayerDescriptor({ const metricSourceKey = getSourceAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field, + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', }); const metricStyleField = { name: metricSourceKey, diff --git a/x-pack/plugins/maps/public/classes/layers/layer.tsx b/x-pack/plugins/maps/public/classes/layers/layer.tsx index 7c76df7f6e877..b982e6452e8cb 100644 --- a/x-pack/plugins/maps/public/classes/layers/layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/layer.tsx @@ -173,12 +173,12 @@ export class AbstractLayer implements ILayer { metrics.forEach((metricsDescriptor: AggDescriptor) => { const originalJoinKey = getJoinAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', rightSourceId: originalJoinId, }); const newJoinKey = getJoinAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', rightSourceId: joinDescriptor.right.id!, }); diff --git a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts index 5dbf07ed2a535..dea551866f4a9 100644 --- a/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/solution_layers/observability/create_layer_descriptor.ts @@ -161,7 +161,7 @@ export function createLayerDescriptor({ const joinId = uuid(); const joinKey = getJoinAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : '', rightSourceId: joinId, }); return VectorLayer.createDescriptor({ @@ -219,7 +219,7 @@ export function createLayerDescriptor({ const metricSourceKey = getSourceAggKey({ aggType: metricsDescriptor.type, - aggFieldName: metricsDescriptor.field, + aggFieldName: 'field' in metricsDescriptor ? metricsDescriptor.field : undefined, }); const metricStyleField = { name: metricSourceKey, diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 543d144efdcc7..753ada9078c2b 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -12,7 +12,7 @@ import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } fro import { FormattedMessage } from '@kbn/i18n/react'; import { MetricSelect } from './metric_select'; import { SingleFieldSelect } from '../single_field_select'; -import { AggDescriptor } from '../../../common/descriptor_types'; +import { AggDescriptor, FieldedAggDescriptor } from '../../../common/descriptor_types'; import { AGG_TYPE } from '../../../common/constants'; import { getTermsFields } from '../../index_pattern_util'; import { IFieldType } from '../../../../../../src/plugins/data/public'; @@ -57,32 +57,41 @@ export function MetricEditor({ if (!metricAggregationType) { return; } - const newMetricProps = { - ...metric, - type: metricAggregationType, - }; // unset field when new agg type does not support currently selected field. - if (metric.field && metricAggregationType !== AGG_TYPE.COUNT) { + if ('field' in metric && metric.field && metricAggregationType !== AGG_TYPE.COUNT) { const fieldsForNewAggType = filterFieldsForAgg(fields, metricAggregationType); const found = fieldsForNewAggType.find((field) => { return field.name === metric.field; }); - if (!found) { - newMetricProps.field = undefined; + if (found) { + onChange({ + type: metricAggregationType, + label: metric.label, + field: metric.field, + }); + } else { + onChange({ + type: metricAggregationType, + label: metric.label, + }); } + } else { + onChange({ + type: metricAggregationType, + label: metric.label, + }); } - - onChange(newMetricProps); }; const onFieldChange = (fieldName?: string) => { - if (!fieldName) { + if (!fieldName || metric.type === AGG_TYPE.COUNT) { return; } onChange({ - ...metric, + label: metric.label, + type: metric.type, field: fieldName, - }); + } as FieldedAggDescriptor); }; const onLabelChange = (e: ChangeEvent) => { onChange({ From ef00fdd7682aba87128bf0739c1b4b8838f1d933 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 11:53:44 -0500 Subject: [PATCH 05/62] remove fluffy export --- .../maps/common/descriptor_types/source_descriptor_types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts index ef48f323a1ad8..c11ee59768a91 100644 --- a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts @@ -40,7 +40,7 @@ export type AbstractESSourceDescriptor = AbstractSourceDescriptor & { applyGlobalTime: boolean; }; -export type AbstractAggDescriptor = { +type AbstractAggDescriptor = { type: AGG_TYPE; label?: string; }; From e640b9d987a620a5c740e47a0b4b42e656dc7a75 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 11:59:03 -0500 Subject: [PATCH 06/62] remove redundant cast --- .../maps/public/components/metrics_editor/metric_editor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 753ada9078c2b..960f550a36e26 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -12,7 +12,7 @@ import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } fro import { FormattedMessage } from '@kbn/i18n/react'; import { MetricSelect } from './metric_select'; import { SingleFieldSelect } from '../single_field_select'; -import { AggDescriptor, FieldedAggDescriptor } from '../../../common/descriptor_types'; +import { AggDescriptor } from '../../../common/descriptor_types'; import { AGG_TYPE } from '../../../common/constants'; import { getTermsFields } from '../../index_pattern_util'; import { IFieldType } from '../../../../../../src/plugins/data/public'; @@ -91,7 +91,7 @@ export function MetricEditor({ label: metric.label, type: metric.type, field: fieldName, - } as FieldedAggDescriptor); + }); }; const onLabelChange = (e: ChangeEvent) => { onChange({ From 6e3463f50d029845fb9a0b40fb721300cdd28490 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 12:21:02 -0500 Subject: [PATCH 07/62] rename to count-agg field --- .../classes/fields/{es_agg_field.ts => count_agg_field.ts} | 2 +- x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts | 4 ++-- .../plugins/maps/public/classes/fields/es_agg_field.test.ts | 4 ++-- .../maps/public/classes/fields/es_fielded_agg_field.ts | 6 +++--- .../maps/public/classes/fields/top_term_percentage_field.ts | 2 +- .../classes/sources/es_agg_source/es_agg_source.test.ts | 2 +- .../public/classes/sources/es_agg_source/es_agg_source.ts | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) rename x-pack/plugins/maps/public/classes/fields/{es_agg_field.ts => count_agg_field.ts} (98%) diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts similarity index 98% rename from x-pack/plugins/maps/public/classes/fields/es_agg_field.ts rename to x-pack/plugins/maps/public/classes/fields/count_agg_field.ts index 4f2be1a023b46..2d4417a41c655 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts @@ -28,7 +28,7 @@ export interface IESAggFieldParams { } // Agg without field. Essentially a count-aggregation. -export class ESAggField implements IESAggField { +export class CountAggField implements IESAggField { private readonly _source: IESAggSource; private readonly _origin: FIELD_ORIGIN; private readonly _label?: string; diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index f06433a1f7cf7..bd6b5cb60c7e8 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -9,7 +9,7 @@ import { IESAggSource } from '../sources/es_agg_source'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { ESDocField } from './es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; -import { ESAggField, IESAggField } from './es_agg_field'; +import { CountAggField, IESAggField } from './count_agg_field'; import { ESFieldedAggField } from './es_fielded_agg_field'; export function esAggFieldsFactory( @@ -20,7 +20,7 @@ export function esAggFieldsFactory( ): IESAggField[] { let aggField; if (aggDescriptor.type === AGG_TYPE.COUNT) { - aggField = new ESAggField({ + aggField = new CountAggField({ label: aggDescriptor.label, source, origin, diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts index 06ddd1f4311f2..baa8d5d131724 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESAggField } from './es_agg_field'; +import { CountAggField } from './count_agg_field'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { IESAggSource } from '../sources/es_agg_source'; import { IIndexPattern } from 'src/plugins/data/public'; @@ -39,7 +39,7 @@ const defaultParams = { describe('supportsFieldMeta', () => { test('Counting aggregations should not support field meta', () => { - const countMetric = new ESAggField({ ...defaultParams }); + const countMetric = new CountAggField({ ...defaultParams }); expect(countMetric.supportsFieldMeta()).toBe(false); }); }); diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts index 52fcc0d7f99c8..209f934ccd1eb 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts @@ -6,8 +6,8 @@ import { IField } from './field'; import { AGG_TYPE } from '../../../common/constants'; -import { ESAggField } from './es_agg_field'; -import { IESAggFieldParams } from './es_agg_field'; +import { CountAggField } from './count_agg_field'; +import { IESAggFieldParams } from './count_agg_field'; import { isMetricCountable } from '../util/is_metric_countable'; export interface IESFieldedAggParams extends IESAggFieldParams { @@ -15,7 +15,7 @@ export interface IESFieldedAggParams extends IESAggFieldParams { aggType: AGG_TYPE; } -export class ESFieldedAggField extends ESAggField { +export class ESFieldedAggField extends CountAggField { private readonly _esDocField?: IField; private readonly _aggType: AGG_TYPE; diff --git a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts b/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts index 50db04d08b2aa..15901c1af6813 100644 --- a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IESAggField } from './es_agg_field'; +import { IESAggField } from './count_agg_field'; import { IVectorSource } from '../sources/vector_source'; import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; import { TOP_TERM_PERCENTAGE_SUFFIX } from '../../../common/constants'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts index d31e8366e4ef4..bc1129c1feff4 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts @@ -6,7 +6,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { IField } from '../../fields/field'; -import { IESAggField } from '../../fields/es_agg_field'; +import { IESAggField } from '../../fields/count_agg_field'; import _ from 'lodash'; import { AGG_TYPE } from '../../../../common/constants'; import { AggDescriptor } from '../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index 5d7d7c6f1fbc7..b743533f8cce1 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -11,7 +11,7 @@ import { IESSource } from '../es_source'; import { AbstractESSource } from '../es_source'; import { esAggFieldsFactory } from '../../fields/es_agg_factory'; import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; -import { IESAggField } from '../../fields/es_agg_field'; +import { IESAggField } from '../../fields/count_agg_field'; import { getSourceAggKey } from '../../../../common/get_agg_key'; import { AbstractESAggSourceDescriptor, AggDescriptor } from '../../../../common/descriptor_types'; import { IndexPattern } from '../../../../../../../src/plugins/data/public'; From fa0d4593a9f427e1e52efd1a1fb9800971ce96d2 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 12:26:21 -0500 Subject: [PATCH 08/62] extract types --- .../public/classes/fields/agg_field_types.ts | 22 +++++++++++++++++++ .../public/classes/fields/count_agg_field.ts | 14 +----------- .../public/classes/fields/es_agg_factory.ts | 3 ++- .../classes/fields/es_fielded_agg_field.ts | 2 +- .../fields/top_term_percentage_field.ts | 2 +- .../es_agg_source/es_agg_source.test.ts | 2 +- .../sources/es_agg_source/es_agg_source.ts | 2 +- 7 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/fields/agg_field_types.ts diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field_types.ts b/x-pack/plugins/maps/public/classes/fields/agg_field_types.ts new file mode 100644 index 0000000000000..c8c5c00a3a1df --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/agg_field_types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IField } from './field'; +import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns'; +import { IESAggSource } from '../sources/es_agg_source'; +import { FIELD_ORIGIN } from '../../../common/constants'; + +export interface IESAggField extends IField { + getValueAggDsl(indexPattern: IndexPattern): unknown | null; + getBucketCount(): number; +} + +export interface IESAggFieldParams { + label?: string; + source: IESAggSource; + origin: FIELD_ORIGIN; + canReadFromGeoJson?: boolean; +} diff --git a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts index 2d4417a41c655..37d8a4e211144 100644 --- a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts @@ -5,28 +5,16 @@ */ import { IndexPattern } from 'src/plugins/data/public'; -import { IField } from './field'; import { IESAggSource } from '../sources/es_agg_source'; import { IVectorSource } from '../sources/vector_source'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; import { ESAggTooltipProperty } from '../tooltips/es_agg_tooltip_property'; +import { IESAggField, IESAggFieldParams } from './agg_field_types'; const TERMS_AGG_SHARD_SIZE = 5; -export interface IESAggField extends IField { - getValueAggDsl(indexPattern: IndexPattern): unknown | null; - getBucketCount(): number; -} - -export interface IESAggFieldParams { - label?: string; - source: IESAggSource; - origin: FIELD_ORIGIN; - canReadFromGeoJson?: boolean; -} - // Agg without field. Essentially a count-aggregation. export class CountAggField implements IESAggField { private readonly _source: IESAggSource; diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index bd6b5cb60c7e8..05ce29810d0dc 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -9,7 +9,8 @@ import { IESAggSource } from '../sources/es_agg_source'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { ESDocField } from './es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; -import { CountAggField, IESAggField } from './count_agg_field'; +import { CountAggField } from './count_agg_field'; +import { IESAggField } from './agg_field_types'; import { ESFieldedAggField } from './es_fielded_agg_field'; export function esAggFieldsFactory( diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts index 209f934ccd1eb..d7e5249091b21 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts @@ -7,8 +7,8 @@ import { IField } from './field'; import { AGG_TYPE } from '../../../common/constants'; import { CountAggField } from './count_agg_field'; -import { IESAggFieldParams } from './count_agg_field'; import { isMetricCountable } from '../util/is_metric_countable'; +import { IESAggFieldParams } from './agg_field_types'; export interface IESFieldedAggParams extends IESAggFieldParams { esDocField?: IField; diff --git a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts b/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts index 15901c1af6813..a66d30e0651c8 100644 --- a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IESAggField } from './count_agg_field'; +import { IESAggField } from './agg_field_types'; import { IVectorSource } from '../sources/vector_source'; import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; import { TOP_TERM_PERCENTAGE_SUFFIX } from '../../../common/constants'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts index bc1129c1feff4..b0eb0f54db1d9 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts @@ -6,7 +6,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { IField } from '../../fields/field'; -import { IESAggField } from '../../fields/count_agg_field'; +import { IESAggField } from '../../fields/agg_field_types'; import _ from 'lodash'; import { AGG_TYPE } from '../../../../common/constants'; import { AggDescriptor } from '../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index b743533f8cce1..f4d7b125b58de 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -11,7 +11,7 @@ import { IESSource } from '../es_source'; import { AbstractESSource } from '../es_source'; import { esAggFieldsFactory } from '../../fields/es_agg_factory'; import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; -import { IESAggField } from '../../fields/count_agg_field'; +import { IESAggField } from '../../fields/agg_field_types'; import { getSourceAggKey } from '../../../../common/get_agg_key'; import { AbstractESAggSourceDescriptor, AggDescriptor } from '../../../../common/descriptor_types'; import { IndexPattern } from '../../../../../../../src/plugins/data/public'; From 750eb78e03d55ea68be971bd2cbb1e164c2b53be Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 12:28:04 -0500 Subject: [PATCH 09/62] rename --- ...fielded_agg_field.test.ts => agg_field.test.ts} | 14 +++++++------- .../{es_fielded_agg_field.ts => agg_field.ts} | 2 +- .../maps/public/classes/fields/es_agg_factory.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) rename x-pack/plugins/maps/public/classes/fields/{es_fielded_agg_field.test.ts => agg_field.test.ts} (73%) rename x-pack/plugins/maps/public/classes/fields/{es_fielded_agg_field.ts => agg_field.ts} (96%) diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/agg_field.test.ts similarity index 73% rename from x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts rename to x-pack/plugins/maps/public/classes/fields/agg_field.test.ts index d4c60941e879e..1721ffddbf62f 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg_field.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFieldedAggField } from './es_fielded_agg_field'; +import { AggField } from './agg_field'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; import { IESAggSource } from '../sources/es_agg_source'; import { IIndexPattern } from 'src/plugins/data/public'; @@ -38,20 +38,20 @@ const defaultParams = { describe('supportsFieldMeta', () => { test('Non-counting aggregations should support field meta', () => { - const avgMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.AVG }); + const avgMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.AVG }); expect(avgMetric.supportsFieldMeta()).toBe(true); - const maxMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.MAX }); + const maxMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MAX }); expect(maxMetric.supportsFieldMeta()).toBe(true); - const minMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.MIN }); + const minMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.MIN }); expect(minMetric.supportsFieldMeta()).toBe(true); - const termsMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.TERMS }); + const termsMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.TERMS }); expect(termsMetric.supportsFieldMeta()).toBe(true); }); test('Counting aggregations should not support field meta', () => { - const sumMetric = new ESFieldedAggField({ ...defaultParams, aggType: AGG_TYPE.SUM }); + const sumMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.SUM }); expect(sumMetric.supportsFieldMeta()).toBe(false); - const uniqueCountMetric = new ESFieldedAggField({ + const uniqueCountMetric = new AggField({ ...defaultParams, aggType: AGG_TYPE.UNIQUE_COUNT, }); diff --git a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg_field.ts similarity index 96% rename from x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts rename to x-pack/plugins/maps/public/classes/fields/agg_field.ts index d7e5249091b21..7a744dacb2425 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_fielded_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg_field.ts @@ -15,7 +15,7 @@ export interface IESFieldedAggParams extends IESAggFieldParams { aggType: AGG_TYPE; } -export class ESFieldedAggField extends CountAggField { +export class AggField extends CountAggField { private readonly _esDocField?: IField; private readonly _aggType: AGG_TYPE; diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index 05ce29810d0dc..c03a0f56c7870 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -11,7 +11,7 @@ import { ESDocField } from './es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; import { CountAggField } from './count_agg_field'; import { IESAggField } from './agg_field_types'; -import { ESFieldedAggField } from './es_fielded_agg_field'; +import { AggField } from './agg_field'; export function esAggFieldsFactory( aggDescriptor: AggDescriptor, @@ -28,7 +28,7 @@ export function esAggFieldsFactory( canReadFromGeoJson, }); } else { - aggField = new ESFieldedAggField({ + aggField = new AggField({ label: aggDescriptor.label, esDocField: 'field' in aggDescriptor && aggDescriptor.field From cb331e09b47a891ff6050313c9d99e0fa557634f Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 14:39:43 -0500 Subject: [PATCH 10/62] boilerplate --- x-pack/plugins/maps/common/constants.ts | 1 + .../source_descriptor_types.ts | 8 +++- .../classes/fields/percentile_agg_field.ts | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index bcfe11851d1ea..653c7fb721c94 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -149,6 +149,7 @@ export enum AGG_TYPE { MIN = 'min', SUM = 'sum', TERMS = 'terms', + PERCENTILE = 'percentile', UNIQUE_COUNT = 'cardinality', } diff --git a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts index c11ee59768a91..18a1b3ad14a6b 100644 --- a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts @@ -60,7 +60,13 @@ export type FieldedAggDescriptor = AbstractAggDescriptor & { field?: string; }; -export type AggDescriptor = CountAggDescriptor | FieldedAggDescriptor; +export type PercentileAggDescriptor = AbstractAggDescriptor & { + type: AGG_TYPE.PERCENTILE; + field?: string; + percentile: number; +}; + +export type AggDescriptor = CountAggDescriptor | FieldedAggDescriptor | PercentileAggDescriptor; export type AbstractESAggSourceDescriptor = AbstractESSourceDescriptor & { metrics: AggDescriptor[]; diff --git a/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts new file mode 100644 index 0000000000000..2f884c05231c2 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IField } from './field'; +import { AGG_TYPE } from '../../../common/constants'; +import { AggField, IESFieldedAggParams } from './agg_field'; +import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns'; +import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; + +export interface IESPercentileAggParams extends IESFieldedAggParams { + esDocField?: IField; + percentile: number; +} + +export class PercentileAggField extends AggField { + private readonly _percentile: number; + constructor(params: IESPercentileAggParams) { + super(params); + this._percentile = params.percentile; + } + + supportsFieldMeta(): boolean { + return true; + } + + canValueBeFormatted(): boolean { + return true; + } + + getValueAggDsl(indexPattern: IndexPattern): unknown | null { + throw new Error('todo'); + } + + getAggType(): AGG_TYPE { + return AGG_TYPE.PERCENTILE; + } +} From 8380a5664d3d7c2cf3ea1918aee7f2d0be054210 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 14:41:33 -0500 Subject: [PATCH 11/62] remove switching --- .../plugins/maps/public/classes/fields/agg_field.ts | 11 +++++++++++ .../maps/public/classes/fields/count_agg_field.ts | 12 +----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg_field.ts index 7a744dacb2425..7e1c7f67a3b5a 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg_field.ts @@ -4,11 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IndexPattern } from 'src/plugins/data/public'; import { IField } from './field'; import { AGG_TYPE } from '../../../common/constants'; import { CountAggField } from './count_agg_field'; import { isMetricCountable } from '../util/is_metric_countable'; import { IESAggFieldParams } from './agg_field_types'; +import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; export interface IESFieldedAggParams extends IESAggFieldParams { esDocField?: IField; @@ -47,6 +49,15 @@ export class AggField extends CountAggField { return this._aggType; } + getValueAggDsl(indexPattern: IndexPattern): unknown { + const field = getField(indexPattern, this.getRootName()); + const aggType = this.getAggType(); + const aggBody = aggType === AGG_TYPE.TERMS ? { size: 1, shard_size: TERMS_AGG_SHARD_SIZE } : {}; + return { + [aggType]: addFieldToDSL(aggBody, field), + }; + } + async getOrdinalFieldMetaRequest(): Promise { return this._esDocField ? await this._esDocField.getOrdinalFieldMetaRequest() : null; } diff --git a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts index 37d8a4e211144..8e80098279462 100644 --- a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts @@ -8,7 +8,6 @@ import { IndexPattern } from 'src/plugins/data/public'; import { IESAggSource } from '../sources/es_agg_source'; import { IVectorSource } from '../sources/vector_source'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; import { ESAggTooltipProperty } from '../tooltips/es_agg_tooltip_property'; import { IESAggField, IESAggFieldParams } from './agg_field_types'; @@ -74,16 +73,7 @@ export class CountAggField implements IESAggField { } getValueAggDsl(indexPattern: IndexPattern): unknown | null { - if (this.getAggType() === AGG_TYPE.COUNT) { - return null; - } - - const field = getField(indexPattern, this.getRootName()); - const aggType = this.getAggType(); - const aggBody = aggType === AGG_TYPE.TERMS ? { size: 1, shard_size: TERMS_AGG_SHARD_SIZE } : {}; - return { - [aggType]: addFieldToDSL(aggBody, field), - }; + return null; } getBucketCount(): number { From 0577e9dc9940a2bdd4651400fd20e6bd4f49ec79 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 14:53:29 -0500 Subject: [PATCH 12/62] remove count type-checking --- .../maps/public/classes/fields/agg_field.ts | 16 ++++++--- .../public/classes/fields/count_agg_field.ts | 36 +++++++++---------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg_field.ts index 7e1c7f67a3b5a..d825f88d48646 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg_field.ts @@ -12,6 +12,8 @@ import { isMetricCountable } from '../util/is_metric_countable'; import { IESAggFieldParams } from './agg_field_types'; import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; +const TERMS_AGG_SHARD_SIZE = 5; + export interface IESFieldedAggParams extends IESAggFieldParams { esDocField?: IField; aggType: AGG_TYPE; @@ -37,27 +39,31 @@ export class AggField extends CountAggField { supportsFieldMeta(): boolean { // count and sum aggregations are not within field bounds so they do not support field meta. - return !isMetricCountable(this.getAggType()); + return !isMetricCountable(this._getAggType()); } canValueBeFormatted(): boolean { - // Do not use field formatters for counting metrics - return ![AGG_TYPE.COUNT, AGG_TYPE.UNIQUE_COUNT].includes(this.getAggType()); + return this._getAggType() !== AGG_TYPE.UNIQUE_COUNT; } - getAggType(): AGG_TYPE { + _getAggType(): AGG_TYPE { return this._aggType; } getValueAggDsl(indexPattern: IndexPattern): unknown { const field = getField(indexPattern, this.getRootName()); - const aggType = this.getAggType(); + const aggType = this._getAggType(); const aggBody = aggType === AGG_TYPE.TERMS ? { size: 1, shard_size: TERMS_AGG_SHARD_SIZE } : {}; return { [aggType]: addFieldToDSL(aggBody, field), }; } + getBucketCount(): number { + // terms aggregation increases the overall number of buckets per split bucket + return this._getAggType() === AGG_TYPE.TERMS ? TERMS_AGG_SHARD_SIZE : 0; + } + async getOrdinalFieldMetaRequest(): Promise { return this._esDocField ? await this._esDocField.getOrdinalFieldMetaRequest() : null; } diff --git a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts index 8e80098279462..3c4cd592e2f4c 100644 --- a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts @@ -12,8 +12,6 @@ import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property' import { ESAggTooltipProperty } from '../tooltips/es_agg_tooltip_property'; import { IESAggField, IESAggFieldParams } from './agg_field_types'; -const TERMS_AGG_SHARD_SIZE = 5; - // Agg without field. Essentially a count-aggregation. export class CountAggField implements IESAggField { private readonly _source: IESAggSource; @@ -28,6 +26,14 @@ export class CountAggField implements IESAggField { this._canReadFromGeoJson = canReadFromGeoJson; } + _getESDocFieldName(): string { + return ''; + } + + _getAggType(): AGG_TYPE { + return AGG_TYPE.COUNT; + } + getSource(): IVectorSource { return this._source; } @@ -37,7 +43,7 @@ export class CountAggField implements IESAggField { } getName(): string { - return this._source.getAggKey(this.getAggType(), this.getRootName()); + return this._source.getAggKey(this._getAggType(), this.getRootName()); } getRootName(): string { @@ -47,11 +53,7 @@ export class CountAggField implements IESAggField { async getLabel(): Promise { return this._label ? this._label - : this._source.getAggLabel(this.getAggType(), this.getRootName()); - } - - getAggType(): AGG_TYPE { - return AGG_TYPE.COUNT; + : this._source.getAggLabel(this._getAggType(), this.getRootName()); } isValid(): boolean { @@ -59,33 +61,27 @@ export class CountAggField implements IESAggField { } async getDataType(): Promise { - return this.getAggType() === AGG_TYPE.TERMS ? 'string' : 'number'; - } - - _getESDocFieldName(): string { - return ''; + return this._getAggType() === AGG_TYPE.TERMS ? 'string' : 'number'; } async createTooltipProperty(value: string | string[] | undefined): Promise { const indexPattern = await this._source.getIndexPattern(); const tooltipProperty = new TooltipProperty(this.getName(), await this.getLabel(), value); - return new ESAggTooltipProperty(tooltipProperty, indexPattern, this, this.getAggType()); + return new ESAggTooltipProperty(tooltipProperty, indexPattern, this, this._getAggType()); } getValueAggDsl(indexPattern: IndexPattern): unknown | null { return null; } - getBucketCount(): number { - // terms aggregation increases the overall number of buckets per split bucket - return this.getAggType() === AGG_TYPE.TERMS ? TERMS_AGG_SHARD_SIZE : 0; - } - supportsFieldMeta(): boolean { - // count and sum aggregations are not within field bounds so they do not support field meta. return false; } + getBucketCount() { + return 0; + } + canValueBeFormatted(): boolean { return false; } From 82863b733a61f3058e5c6e99e8dca520d7b59575 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 15:26:59 -0500 Subject: [PATCH 13/62] more boilerplate --- .../public/classes/fields/es_agg_factory.ts | 9 +++++++ .../classes/fields/percentile_agg_field.ts | 26 +++++++++++++++---- .../blended_vector_layer.ts | 4 ++- .../metrics_editor/metric_select.tsx | 6 +++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts index c03a0f56c7870..10329260430f1 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts @@ -12,6 +12,7 @@ import { TopTermPercentageField } from './top_term_percentage_field'; import { CountAggField } from './count_agg_field'; import { IESAggField } from './agg_field_types'; import { AggField } from './agg_field'; +import { PercentileAggField } from './percentile_agg_field'; export function esAggFieldsFactory( aggDescriptor: AggDescriptor, @@ -27,6 +28,14 @@ export function esAggFieldsFactory( origin, canReadFromGeoJson, }); + } else if (aggDescriptor.type === AGG_TYPE.PERCENTILE) { + aggField = new PercentileAggField({ + label: aggDescriptor.label, + source, + origin, + canReadFromGeoJson, + percentile: aggDescriptor.percentile, + }); } else { aggField = new AggField({ label: aggDescriptor.label, diff --git a/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts index 2f884c05231c2..a0a013db332fd 100644 --- a/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts @@ -6,19 +6,23 @@ import { IField } from './field'; import { AGG_TYPE } from '../../../common/constants'; -import { AggField, IESFieldedAggParams } from './agg_field'; +import { AggField } from './agg_field'; import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns'; -import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; +import { IESAggField, IESAggFieldParams } from './agg_field_types'; +import { CountAggField } from './count_agg_field'; +import { ESDocField } from './es_doc_field'; -export interface IESPercentileAggParams extends IESFieldedAggParams { +export interface IESPercentileAggParams extends IESAggFieldParams { esDocField?: IField; percentile: number; } -export class PercentileAggField extends AggField { +export class PercentileAggField extends CountAggField implements IESAggField { private readonly _percentile: number; + private readonly _esDocField: ESDocField; constructor(params: IESPercentileAggParams) { super(params); + this._esDocField = params.esDocField; this._percentile = params.percentile; } @@ -34,7 +38,19 @@ export class PercentileAggField extends AggField { throw new Error('todo'); } - getAggType(): AGG_TYPE { + _getAggType(): AGG_TYPE { return AGG_TYPE.PERCENTILE; } + + async getOrdinalFieldMetaRequest(): Promise { + return this._esDocField ? await this._esDocField.getOrdinalFieldMetaRequest() : null; + } + + async getCategoricalFieldMetaRequest(size: number): Promise { + return this._esDocField ? await this._esDocField.getCategoricalFieldMetaRequest(size) : null; + } + + isValid(): boolean { + return !!this._esDocField; + } } diff --git a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts index 2ab8a70f2e4df..64bf547cefd7f 100644 --- a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts @@ -47,7 +47,9 @@ interface CountData { isSyncClustered: boolean; } -function getAggType(dynamicProperty: IDynamicStyleProperty): AGG_TYPE { +function getAggType( + dynamicProperty: IDynamicStyleProperty +): AGG_TYPE.AVG | AGG_TYPE.TERMS { return dynamicProperty.isOrdinal() ? AGG_TYPE.AVG : AGG_TYPE.TERMS; } diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx index 197c5466fe0fd..8dbe00c930778 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx @@ -52,6 +52,12 @@ const AGG_OPTIONS = [ }), value: AGG_TYPE.UNIQUE_COUNT, }, + { + label: i18n.translate('xpack.maps.metricSelect.percentileDropDownOptionLabel', { + defaultMessage: 'Percentile', + }), + value: AGG_TYPE.PERCENTILE, + }, ]; type Props = Omit, 'onChange'> & { From 0c8ea4fdf418a90ad6eb17654b443228a7fbaf0d Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 15:36:33 -0500 Subject: [PATCH 14/62] simplify --- .../plugins/maps/public/classes/fields/agg_field.ts | 12 ++++++++---- .../maps/public/classes/fields/count_agg_field.ts | 8 ++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg_field.ts index d825f88d48646..3356be650e399 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg_field.ts @@ -29,10 +29,6 @@ export class AggField extends CountAggField { this._aggType = params.aggType; } - _getESDocFieldName(): string { - return this._esDocField ? this._esDocField.getName() : ''; - } - isValid(): boolean { return !!this._esDocField; } @@ -59,6 +55,14 @@ export class AggField extends CountAggField { }; } + getRootName(): string { + return this._esDocField ? this._esDocField.getName() : ''; + } + + async getDataType(): Promise { + return this._getAggType() === AGG_TYPE.TERMS ? 'string' : 'number'; + } + getBucketCount(): number { // terms aggregation increases the overall number of buckets per split bucket return this._getAggType() === AGG_TYPE.TERMS ? TERMS_AGG_SHARD_SIZE : 0; diff --git a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts index 3c4cd592e2f4c..51a732c0a0a67 100644 --- a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts @@ -26,10 +26,6 @@ export class CountAggField implements IESAggField { this._canReadFromGeoJson = canReadFromGeoJson; } - _getESDocFieldName(): string { - return ''; - } - _getAggType(): AGG_TYPE { return AGG_TYPE.COUNT; } @@ -47,7 +43,7 @@ export class CountAggField implements IESAggField { } getRootName(): string { - return this._getESDocFieldName(); + return ''; } async getLabel(): Promise { @@ -61,7 +57,7 @@ export class CountAggField implements IESAggField { } async getDataType(): Promise { - return this._getAggType() === AGG_TYPE.TERMS ? 'string' : 'number'; + return 'number'; } async createTooltipProperty(value: string | string[] | undefined): Promise { From 43ef71bfc53217e1e49346363571d7d3e95672ea Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 12 Nov 2020 15:56:32 -0500 Subject: [PATCH 15/62] move files --- .../classes/fields/{ => agg}/agg_field.test.ts | 4 ++-- .../public/classes/fields/{ => agg}/agg_field.ts | 14 +++++++------- .../classes/fields/{ => agg}/agg_field_types.ts | 10 +++++----- .../count_agg_field.test.ts} | 4 ++-- .../classes/fields/{ => agg}/count_agg_field.ts | 14 +++++++------- .../fields/{ => agg}/es_agg_factory.test.ts | 6 +++--- .../classes/fields/{ => agg}/es_agg_factory.ts | 8 ++++---- .../maps/public/classes/fields/agg/index.ts | 8 ++++++++ .../fields/{ => agg}/top_term_percentage_field.ts | 7 +++---- .../sources/es_agg_source/es_agg_source.test.ts | 2 +- .../classes/sources/es_agg_source/es_agg_source.ts | 3 +-- 11 files changed, 43 insertions(+), 37 deletions(-) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/agg_field.test.ts (93%) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/agg_field.ts (84%) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/agg_field_types.ts (61%) rename x-pack/plugins/maps/public/classes/fields/{es_agg_field.test.ts => agg/count_agg_field.test.ts} (89%) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/count_agg_field.ts (83%) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/es_agg_factory.test.ts (84%) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/es_agg_factory.ts (85%) create mode 100644 x-pack/plugins/maps/public/classes/fields/agg/index.ts rename x-pack/plugins/maps/public/classes/fields/{ => agg}/top_term_percentage_field.ts (88%) diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.test.ts similarity index 93% rename from x-pack/plugins/maps/public/classes/fields/agg_field.test.ts rename to x-pack/plugins/maps/public/classes/fields/agg/agg_field.test.ts index 1721ffddbf62f..49a599326d54c 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.test.ts @@ -5,8 +5,8 @@ */ import { AggField } from './agg_field'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { IESAggSource } from '../sources/es_agg_source'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { IESAggSource } from '../../sources/es_agg_source'; import { IIndexPattern } from 'src/plugins/data/public'; const mockIndexPattern = { diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts similarity index 84% rename from x-pack/plugins/maps/public/classes/fields/agg_field.ts rename to x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts index 3356be650e399..31595327a64b8 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field.ts @@ -5,16 +5,16 @@ */ import { IndexPattern } from 'src/plugins/data/public'; -import { IField } from './field'; -import { AGG_TYPE } from '../../../common/constants'; +import { AGG_TYPE } from '../../../../common/constants'; import { CountAggField } from './count_agg_field'; -import { isMetricCountable } from '../util/is_metric_countable'; -import { IESAggFieldParams } from './agg_field_types'; -import { addFieldToDSL, getField } from '../../../common/elasticsearch_util'; +import { isMetricCountable } from '../../util/is_metric_countable'; +import { CountAggFieldParams } from './agg_field_types'; +import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; +import { IField } from '../field'; const TERMS_AGG_SHARD_SIZE = 5; -export interface IESFieldedAggParams extends IESAggFieldParams { +export interface AggFieldParams extends CountAggFieldParams { esDocField?: IField; aggType: AGG_TYPE; } @@ -23,7 +23,7 @@ export class AggField extends CountAggField { private readonly _esDocField?: IField; private readonly _aggType: AGG_TYPE; - constructor(params: IESFieldedAggParams) { + constructor(params: AggFieldParams) { super(params); this._esDocField = params.esDocField; this._aggType = params.aggType; diff --git a/x-pack/plugins/maps/public/classes/fields/agg_field_types.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts similarity index 61% rename from x-pack/plugins/maps/public/classes/fields/agg_field_types.ts rename to x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts index c8c5c00a3a1df..74f03a3f31909 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg_field_types.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts @@ -4,17 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IField } from './field'; -import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns'; -import { IESAggSource } from '../sources/es_agg_source'; -import { FIELD_ORIGIN } from '../../../common/constants'; +import { IField } from '../field'; +import { IndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns/index_patterns'; +import { IESAggSource } from '../../sources/es_agg_source'; +import { FIELD_ORIGIN } from '../../../../common/constants'; export interface IESAggField extends IField { getValueAggDsl(indexPattern: IndexPattern): unknown | null; getBucketCount(): number; } -export interface IESAggFieldParams { +export interface CountAggFieldParams { label?: string; source: IESAggSource; origin: FIELD_ORIGIN; diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.test.ts similarity index 89% rename from x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts rename to x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.test.ts index baa8d5d131724..a313b59643c34 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.test.ts @@ -5,8 +5,8 @@ */ import { CountAggField } from './count_agg_field'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { IESAggSource } from '../sources/es_agg_source'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { IESAggSource } from '../../sources/es_agg_source'; import { IIndexPattern } from 'src/plugins/data/public'; const mockIndexPattern = { diff --git a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts similarity index 83% rename from x-pack/plugins/maps/public/classes/fields/count_agg_field.ts rename to x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts index 51a732c0a0a67..a4562c91e92a6 100644 --- a/x-pack/plugins/maps/public/classes/fields/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts @@ -5,12 +5,12 @@ */ import { IndexPattern } from 'src/plugins/data/public'; -import { IESAggSource } from '../sources/es_agg_source'; -import { IVectorSource } from '../sources/vector_source'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; -import { ESAggTooltipProperty } from '../tooltips/es_agg_tooltip_property'; -import { IESAggField, IESAggFieldParams } from './agg_field_types'; +import { IESAggSource } from '../../sources/es_agg_source'; +import { IVectorSource } from '../../sources/vector_source'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property'; +import { ESAggTooltipProperty } from '../../tooltips/es_agg_tooltip_property'; +import { IESAggField, CountAggFieldParams } from './agg_field_types'; // Agg without field. Essentially a count-aggregation. export class CountAggField implements IESAggField { @@ -19,7 +19,7 @@ export class CountAggField implements IESAggField { private readonly _label?: string; private readonly _canReadFromGeoJson: boolean; - constructor({ label, source, origin, canReadFromGeoJson = true }: IESAggFieldParams) { + constructor({ label, source, origin, canReadFromGeoJson = true }: CountAggFieldParams) { this._source = source; this._origin = origin; this._label = label; diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts similarity index 84% rename from x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts rename to x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts index b06fc6b959628..cb0bb51e374fb 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts @@ -5,9 +5,9 @@ */ import { esAggFieldsFactory } from './es_agg_factory'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { IESAggSource } from '../sources/es_agg_source'; -import { IIndexPattern } from '../../../../../../src/plugins/data/common/index_patterns'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { IESAggSource } from '../../sources/es_agg_source'; +import { IIndexPattern } from '../../../../../../../src/plugins/data/common/index_patterns'; const mockIndexPattern = { title: 'wildIndex', diff --git a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts similarity index 85% rename from x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts rename to x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts index c03a0f56c7870..a734432d03ca2 100644 --- a/x-pack/plugins/maps/public/classes/fields/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AggDescriptor } from '../../../common/descriptor_types'; -import { IESAggSource } from '../sources/es_agg_source'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../common/constants'; -import { ESDocField } from './es_doc_field'; +import { AggDescriptor } from '../../../../common/descriptor_types'; +import { IESAggSource } from '../../sources/es_agg_source'; +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { ESDocField } from '../es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; import { CountAggField } from './count_agg_field'; import { IESAggField } from './agg_field_types'; diff --git a/x-pack/plugins/maps/public/classes/fields/agg/index.ts b/x-pack/plugins/maps/public/classes/fields/agg/index.ts new file mode 100644 index 0000000000000..e6aeb7ba9e7b1 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/agg/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { esAggFieldsFactory } from './es_agg_factory'; +export { IESAggField } from './agg_field_types'; diff --git a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts similarity index 88% rename from x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts rename to x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts index a66d30e0651c8..e3d62afaca921 100644 --- a/x-pack/plugins/maps/public/classes/fields/top_term_percentage_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts @@ -5,10 +5,9 @@ */ import { IESAggField } from './agg_field_types'; -import { IVectorSource } from '../sources/vector_source'; -import { ITooltipProperty, TooltipProperty } from '../tooltips/tooltip_property'; -import { TOP_TERM_PERCENTAGE_SUFFIX } from '../../../common/constants'; -import { FIELD_ORIGIN } from '../../../common/constants'; +import { IVectorSource } from '../../sources/vector_source'; +import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property'; +import { TOP_TERM_PERCENTAGE_SUFFIX, FIELD_ORIGIN } from '../../../../common/constants'; export class TopTermPercentageField implements IESAggField { private readonly _topTermAggField: IESAggField; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts index b0eb0f54db1d9..a731fcee3f6f5 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.test.ts @@ -6,7 +6,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { IField } from '../../fields/field'; -import { IESAggField } from '../../fields/agg_field_types'; +import { IESAggField } from '../../fields/agg'; import _ from 'lodash'; import { AGG_TYPE } from '../../../../common/constants'; import { AggDescriptor } from '../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index f4d7b125b58de..b88ae9a4727a8 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -9,9 +9,8 @@ import { Adapters } from 'src/plugins/inspector/public'; import { GeoJsonProperties } from 'geojson'; import { IESSource } from '../es_source'; import { AbstractESSource } from '../es_source'; -import { esAggFieldsFactory } from '../../fields/es_agg_factory'; +import { esAggFieldsFactory, IESAggField } from '../../fields/agg'; import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; -import { IESAggField } from '../../fields/agg_field_types'; import { getSourceAggKey } from '../../../../common/get_agg_key'; import { AbstractESAggSourceDescriptor, AggDescriptor } from '../../../../common/descriptor_types'; import { IndexPattern } from '../../../../../../../src/plugins/data/public'; From d3103e98543c5c00c5b5a3814010fc1d77f43ad6 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Sun, 15 Nov 2020 19:33:28 -0500 Subject: [PATCH 16/62] boilerplate --- x-pack/plugins/maps/common/constants.ts | 2 ++ .../source_descriptor_types.ts | 2 +- .../common/elasticsearch_util/es_agg_utils.ts | 15 ++++++-- .../classes/fields/agg/es_agg_factory.ts | 11 ++++-- .../fields/{ => agg}/percentile_agg_field.ts | 34 +++++++++++++------ .../create_region_map_layer_descriptor.ts | 11 +++--- .../create_tile_map_layer_descriptor.ts | 14 ++++++-- .../sources/es_agg_source/es_agg_source.ts | 2 +- 8 files changed, 67 insertions(+), 24 deletions(-) rename x-pack/plugins/maps/public/classes/fields/{ => agg}/percentile_agg_field.ts (56%) diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 653c7fb721c94..8ca77ab89d55f 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -171,6 +171,8 @@ export const GEOTILE_GRID_AGG_NAME = 'gridSplit'; export const GEOCENTROID_AGG_NAME = 'gridCentroid'; export const TOP_TERM_PERCENTAGE_SUFFIX = '__percentage'; +export const DEFAULT_PERCENTILE = 50; +export const PERCENTILE_AGG_NAME = 'percentile'; export const COUNT_PROP_LABEL = i18n.translate('xpack.maps.aggs.defaultCountLabel', { defaultMessage: 'count', diff --git a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts index 18a1b3ad14a6b..67bfaf849f192 100644 --- a/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts +++ b/x-pack/plugins/maps/common/descriptor_types/source_descriptor_types.ts @@ -63,7 +63,7 @@ export type FieldedAggDescriptor = AbstractAggDescriptor & { export type PercentileAggDescriptor = AbstractAggDescriptor & { type: AGG_TYPE.PERCENTILE; field?: string; - percentile: number; + percentile?: number; }; export type AggDescriptor = CountAggDescriptor | FieldedAggDescriptor | PercentileAggDescriptor; diff --git a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts index 99c1fa3070fb9..e0cf0fb166c8e 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import _ from 'lodash'; import { IndexPattern, IFieldType } from '../../../../../src/plugins/data/common'; -import { TOP_TERM_PERCENTAGE_SUFFIX } from '../constants'; +import { AGG_TYPE, TOP_TERM_PERCENTAGE_SUFFIX } from '../constants'; export type BucketProperties = Record; export type PropertiesMap = Map; @@ -46,6 +46,7 @@ export function extractPropertiesFromBucket( continue; } + // todo: push these implementations in the IAggFields if (_.has(bucket[key], 'value')) { properties[key] = bucket[key].value; } else if (_.has(bucket[key], 'buckets')) { @@ -63,7 +64,17 @@ export function extractPropertiesFromBucket( ); } } else { - properties[key] = bucket[key]; + if (key.startsWith(AGG_TYPE.PERCENTILE)) { + const values = bucket[key].values; + for (const k in values) { + if (values.hasOwnProperty(k)) { + properties[key] = values[k]; + break; + } + } + } else { + properties[key] = bucket[key]; + } } } return properties; diff --git a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts index 46a9c47fd00f6..cc70caff62717 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.ts @@ -6,7 +6,7 @@ import { AggDescriptor } from '../../../../common/descriptor_types'; import { IESAggSource } from '../../sources/es_agg_source'; -import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { AGG_TYPE, DEFAULT_PERCENTILE, FIELD_ORIGIN } from '../../../../common/constants'; import { ESDocField } from '../es_doc_field'; import { TopTermPercentageField } from './top_term_percentage_field'; import { CountAggField } from './count_agg_field'; @@ -31,10 +31,17 @@ export function esAggFieldsFactory( } else if (aggDescriptor.type === AGG_TYPE.PERCENTILE) { aggField = new PercentileAggField({ label: aggDescriptor.label, + esDocField: + 'field' in aggDescriptor && aggDescriptor.field + ? new ESDocField({ fieldName: aggDescriptor.field, source, origin }) + : undefined, + percentile: + 'percentile' in aggDescriptor && typeof aggDescriptor.percentile === 'number' + ? aggDescriptor.percentile + : DEFAULT_PERCENTILE, source, origin, canReadFromGeoJson, - percentile: aggDescriptor.percentile, }); } else { aggField = new AggField({ diff --git a/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts similarity index 56% rename from x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts rename to x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index a0a013db332fd..33bf3790dfbfb 100644 --- a/x-pack/plugins/maps/public/classes/fields/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -4,23 +4,22 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IField } from './field'; -import { AGG_TYPE } from '../../../common/constants'; -import { AggField } from './agg_field'; -import { IndexPattern } from '../../../../../../src/plugins/data/common/index_patterns/index_patterns'; -import { IESAggField, IESAggFieldParams } from './agg_field_types'; +import { IndexPattern } from 'src/plugins/data/common/index_patterns/index_patterns'; +import { IField } from '../field'; +import { AGG_TYPE } from '../../../../common/constants'; +import { IESAggField, CountAggFieldParams } from './agg_field_types'; import { CountAggField } from './count_agg_field'; -import { ESDocField } from './es_doc_field'; +import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; -export interface IESPercentileAggParams extends IESAggFieldParams { +export interface PercentileAggParams extends CountAggFieldParams { esDocField?: IField; percentile: number; } export class PercentileAggField extends CountAggField implements IESAggField { private readonly _percentile: number; - private readonly _esDocField: ESDocField; - constructor(params: IESPercentileAggParams) { + private readonly _esDocField?: IField; + constructor(params: PercentileAggParams) { super(params); this._esDocField = params.esDocField; this._percentile = params.percentile; @@ -34,8 +33,21 @@ export class PercentileAggField extends CountAggField implements IESAggField { return true; } - getValueAggDsl(indexPattern: IndexPattern): unknown | null { - throw new Error('todo'); + getName() { + return `${super.getName()}_${this._percentile}`; + } + + getRootName(): string { + return this._esDocField ? this._esDocField.getName() : ''; + } + + getValueAggDsl(indexPattern: IndexPattern): unknown { + const field = getField(indexPattern, this.getRootName()); + const dsl = addFieldToDSL({}, field); + dsl.percents = [this._percentile]; + return { + percentiles: dsl, + }; } _getAggType(): AGG_TYPE { diff --git a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts index 6f9bb686459b5..42229b5bd82d8 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_region_map_layer_descriptor.ts @@ -21,7 +21,6 @@ import { import { VectorStyle } from '../styles/vector/vector_style'; import { EMSFileSource } from '../sources/ems_file_source'; // @ts-ignore -import { ESGeoGridSource } from '../sources/es_geo_grid_source'; import { VectorLayer } from './vector_layer/vector_layer'; import { getDefaultDynamicProperties } from '../styles/vector/vector_style_defaults'; import { NUMERICAL_COLOR_PALETTES } from '../styles/color_palettes'; @@ -35,9 +34,13 @@ export function createAggDescriptor(metricAgg: string, metricFieldName?: string) }); const aggType = aggTypeKey ? AGG_TYPE[aggTypeKey as keyof typeof AGG_TYPE] : undefined; - return aggType && metricFieldName - ? { type: aggType, field: metricFieldName } - : { type: AGG_TYPE.COUNT }; + if (!aggType || aggType === AGG_TYPE.COUNT || !metricFieldName) { + return { type: AGG_TYPE.COUNT }; + } else if (aggType === AGG_TYPE.PERCENTILE) { + return { type: aggType, field: metricFieldName, percentile: 50 }; + } else { + return { type: aggType, field: metricFieldName }; + } } export function createRegionMapLayerDescriptor({ diff --git a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts index 5b89373f2db48..260974164da5b 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts @@ -59,9 +59,17 @@ export function createAggDescriptor( }); const aggType = aggTypeKey ? AGG_TYPE[aggTypeKey as keyof typeof AGG_TYPE] : undefined; - return aggType && metricFieldName && (!isHeatmap(mapType) || isMetricCountable(aggType)) - ? { type: aggType, field: metricFieldName } - : { type: AGG_TYPE.COUNT }; + if (!aggType || aggType === AGG_TYPE.COUNT || !metricFieldName) { + return { type: AGG_TYPE.COUNT }; + } else if (aggType === AGG_TYPE.PERCENTILE) { + return { type: aggType, field: metricFieldName, percentile: 50 }; + } else { + if (isHeatmap(mapType) && isMetricCountable(aggType)) { + return { type: AGG_TYPE.COUNT }; + } else { + return { type: aggType, field: metricFieldName }; + } + } } export function createTileMapLayerDescriptor({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index b88ae9a4727a8..2f7a16159bcd5 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -28,7 +28,7 @@ export interface IESAggSource extends IESSource { getValueAggsDsl(indexPattern: IndexPattern): { [key: string]: unknown }; } -export abstract class AbstractESAggSource extends AbstractESSource { +export abstract class AbstractESAggSource extends AbstractESSource implements IESAggSource { private readonly _metricFields: IESAggField[]; private readonly _canReadFromGeoJson: boolean; From e1fca30981c672370145f8200189165eb3bf52fa Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Sun, 15 Nov 2020 19:44:56 -0500 Subject: [PATCH 17/62] type fix --- .../maps/public/classes/fields/agg/percentile_agg_field.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index 33bf3790dfbfb..8016e552d32fe 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -43,7 +43,7 @@ export class PercentileAggField extends CountAggField implements IESAggField { getValueAggDsl(indexPattern: IndexPattern): unknown { const field = getField(indexPattern, this.getRootName()); - const dsl = addFieldToDSL({}, field); + const dsl: Record = addFieldToDSL({}, field); dsl.percents = [this._percentile]; return { percentiles: dsl, From 25f5960fc697250c4a0436aaf19ea3d00c9fa2ea Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Sun, 15 Nov 2020 20:33:35 -0500 Subject: [PATCH 18/62] add slider --- .../fields/agg/percentile_agg_field.ts | 10 +++ .../metrics_editor/metric_editor.tsx | 62 ++++++++++++++++--- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index 8016e552d32fe..ee81194ba2665 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -33,6 +33,16 @@ export class PercentileAggField extends CountAggField implements IESAggField { return true; } + async getLabel(): Promise { + const suffix = this._percentile === 1 ? 'st' : this._percentile === 2 ? 'nd' : 'th'; + return this._label + ? this._label + : `${this._percentile}${suffix} ${this._source.getAggLabel( + this._getAggType(), + this.getRootName() + )}`; + } + getName() { return `${super.getName()}_${this._percentile}`; } diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 960f550a36e26..06f29e4e277fd 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -7,13 +7,19 @@ import React, { ChangeEvent, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiComboBoxOptionOption, + EuiFieldText, + EuiFormRow, + EuiRange, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { MetricSelect } from './metric_select'; import { SingleFieldSelect } from '../single_field_select'; import { AggDescriptor } from '../../../common/descriptor_types'; -import { AGG_TYPE } from '../../../common/constants'; +import { AGG_TYPE, DEFAULT_PERCENTILE } from '../../../common/constants'; import { getTermsFields } from '../../index_pattern_util'; import { IFieldType } from '../../../../../../src/plugins/data/public'; @@ -65,11 +71,20 @@ export function MetricEditor({ return field.name === metric.field; }); if (found) { - onChange({ - type: metricAggregationType, - label: metric.label, - field: metric.field, - }); + if (metricAggregationType === AGG_TYPE.PERCENTILE) { + onChange({ + type: metricAggregationType, + label: metric.label, + field: metric.field, + percentile: metric.percentile, + }); + } else { + onChange({ + type: metricAggregationType, + label: metric.label, + field: metric.field, + }); + } } else { onChange({ type: metricAggregationType, @@ -93,6 +108,15 @@ export function MetricEditor({ field: fieldName, }); }; + const onPercentileChange = (e: ChangeEvent) => { + if (metric.type !== AGG_TYPE.PERCENTILE) { + return; + } + onChange({ + ...metric, + percentile: parseInt(e.target.value, 10), + }); + }; const onLabelChange = (e: ChangeEvent) => { onChange({ ...metric, @@ -123,6 +147,29 @@ export function MetricEditor({ ); } + let percentileSelect; + if (metric.type === AGG_TYPE.PERCENTILE) { + percentileSelect = ( + + + + ); + } + let labelInput; if (metric.type) { labelInput = ( @@ -180,6 +227,7 @@ export function MetricEditor({ {fieldSelect} + {percentileSelect} {labelInput} {removeButton} From 211bb3c6c89470836a59bde60aeae0124fdf2a2b Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Sun, 15 Nov 2020 20:41:30 -0500 Subject: [PATCH 19/62] type fixes --- .../maps/public/classes/fields/agg/count_agg_field.ts | 4 ++-- .../components/metrics_editor/metric_editor.tsx | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts index a4562c91e92a6..34ec3fd7082ea 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts @@ -14,9 +14,9 @@ import { IESAggField, CountAggFieldParams } from './agg_field_types'; // Agg without field. Essentially a count-aggregation. export class CountAggField implements IESAggField { - private readonly _source: IESAggSource; + readonly _source: IESAggSource; private readonly _origin: FIELD_ORIGIN; - private readonly _label?: string; + readonly _label?: string; private readonly _canReadFromGeoJson: boolean; constructor({ label, source, origin, canReadFromGeoJson = true }: CountAggFieldParams) { diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 06f29e4e277fd..6c51faff1c6df 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -72,12 +72,15 @@ export function MetricEditor({ }); if (found) { if (metricAggregationType === AGG_TYPE.PERCENTILE) { - onChange({ + const m = { type: metricAggregationType, label: metric.label, field: metric.field, - percentile: metric.percentile, - }); + }; + if ('percentile' in metric) { + m.percentile = metric.percentile; + } + onChange(m); } else { onChange({ type: metricAggregationType, @@ -108,7 +111,7 @@ export function MetricEditor({ field: fieldName, }); }; - const onPercentileChange = (e: ChangeEvent) => { + const onPercentileChange = (e: MouseEvent) => { if (metric.type !== AGG_TYPE.PERCENTILE) { return; } From 6105ba722f1be4b7483055c2d8052755b63c9c26 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 17 Nov 2020 16:09:09 -0500 Subject: [PATCH 20/62] init commit --- .../maps/public/actions/layer_actions.ts | 56 +++- .../classes/fields/agg/agg_field_types.ts | 1 + .../classes/fields/agg/count_agg_field.ts | 4 + .../properties/dynamic_style_property.tsx | 17 ++ .../styles/vector/style_fields_helper.ts | 2 +- .../styles/vector/vector_style.test.js | 8 +- .../classes/styles/vector/vector_style.tsx | 283 ++++++++++++------ .../maps/public/selectors/map_selectors.ts | 2 +- 8 files changed, 252 insertions(+), 121 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index c8c9f6ba40041..71a914668009c 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -45,6 +45,10 @@ import { IVectorLayer } from '../classes/layers/vector_layer/vector_layer'; import { LAYER_STYLE_TYPE, LAYER_TYPE } from '../../common/constants'; import { IVectorStyle } from '../classes/styles/vector/vector_style'; import { notifyLicensedFeatureUsage } from '../licensed_features'; +import { IVectorSource } from '../classes/sources/vector_source'; +import { IESSource } from '../classes/sources/es_source'; +import { IESAggSource } from '../classes/sources/es_agg_source'; +import { IESAggField } from '../classes/fields/agg'; export function trackCurrentLayerState(layerId: string) { return { @@ -280,18 +284,37 @@ export function updateSourceProp( value: unknown, newLayerType?: LAYER_TYPE ) { - return async (dispatch: ThunkDispatch) => { - dispatch({ - type: UPDATE_SOURCE_PROP, - layerId, - propName, - value, - }); - if (newLayerType) { - dispatch(updateLayerType(layerId, newLayerType)); + return async ( + dispatch: ThunkDispatch, + getState: () => MapStoreState + ) => { + if (propName === 'metrics') { + const layer = getLayerById(layerId, getState()); + const oldFields = await (layer as IVectorLayer).getFields(); + dispatch({ + type: UPDATE_SOURCE_PROP, + layerId, + propName, + value, + }); + if (newLayerType) { + dispatch(updateLayerType(layerId, newLayerType)); + } + await dispatch(updateStyleProperties(layerId, oldFields)); + dispatch(syncDataForLayerId(layerId)); + } else { + dispatch({ + type: UPDATE_SOURCE_PROP, + layerId, + propName, + value, + }); + if (newLayerType) { + dispatch(updateLayerType(layerId, newLayerType)); + } + await dispatch(updateStyleProperties(layerId)); + dispatch(syncDataForLayerId(layerId)); } - await dispatch(clearMissingStyleProperties(layerId)); - dispatch(syncDataForLayerId(layerId)); }; } @@ -422,7 +445,7 @@ function removeLayerFromLayerList(layerId: string) { }; } -export function clearMissingStyleProperties(layerId: string) { +export function updateStyleProperties(layerId: string, oldFields: IESAggField[]) { return async ( dispatch: ThunkDispatch, getState: () => MapStoreState @@ -441,9 +464,10 @@ export function clearMissingStyleProperties(layerId: string) { const { hasChanges, nextStyleDescriptor, - } = await (style as IVectorStyle).getDescriptorWithMissingStylePropsRemoved( - nextFields, - getMapColors(getState()) + } = await (style as IVectorStyle).getDescriptorWithUpdatedStyleProps( + nextFields as IESAggField[], + getMapColors(getState()), + oldFields ); if (hasChanges && nextStyleDescriptor) { dispatch(updateLayerStyle(layerId, nextStyleDescriptor)); @@ -491,7 +515,7 @@ export function setJoinsForLayer(layer: ILayer, joins: JoinDescriptor[]) { joins, }); - await dispatch(clearMissingStyleProperties(layer.getId())); + await dispatch(updateStyleProperties(layer.getId())); dispatch(syncDataForLayerId(layer.getId())); }; } diff --git a/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts index 74f03a3f31909..8ed297a13efa3 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts @@ -12,6 +12,7 @@ import { FIELD_ORIGIN } from '../../../../common/constants'; export interface IESAggField extends IField { getValueAggDsl(indexPattern: IndexPattern): unknown | null; getBucketCount(): number; + isEqual(field: IESAggField): boolean; } export interface CountAggFieldParams { diff --git a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts index a4562c91e92a6..ff6dbbce6f095 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts @@ -97,4 +97,8 @@ export class CountAggField implements IESAggField { canReadFromGeoJson(): boolean { return this._canReadFromGeoJson; } + + isEqual(field: IESAggField) { + return field.getName() === this.getName(); + } } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index 98b58def905eb..bcd72f8beed7c 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -26,12 +26,14 @@ import { FieldMetaOptions, RangeFieldMeta, StyleMetaData, + StylePropertyField, } from '../../../../../common/descriptor_types'; import { IField } from '../../../fields/field'; import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; import { IJoin } from '../../../joins/join'; import { IVectorStyle } from '../vector_style'; import { getComputedFieldName } from '../style_util'; +import { IESAggField } from '../../../fields/agg'; export interface IDynamicStyleProperty extends IStyleProperty { getFieldMetaOptions(): FieldMetaOptions; @@ -48,6 +50,10 @@ export interface IDynamicStyleProperty extends IStyleProperty { pluckOrdinalStyleMetaFromFeatures(features: Feature[]): RangeFieldMeta | null; pluckCategoricalStyleMetaFromFeatures(features: Feature[]): CategoryFieldMeta | null; getValueSuggestions(query: string): Promise; + rectifyFieldDescriptor( + currentField: IESAggField, + previousFieldDescriptor: StylePropertyField + ): StylePropertyField | null; enrichGeoJsonAndMbFeatureState( featureCollection: FeatureCollection, mbMap: MbMap, @@ -240,6 +246,17 @@ export class DynamicStyleProperty } as RangeFieldMeta); } + rectifyFieldDescriptor( + currentField: IESAggField, + previousFieldDescriptor: StylePropertyField + ): StylePropertyField | null { + // Todo: individual style property classes would need to override this with "smart" behavior + return { + origin: previousFieldDescriptor.origin, + name: currentField.getName(), + }; + } + pluckCategoricalStyleMetaFromFeatures(features: Feature[]) { const size = this.getNumberOfCategories(); if (!this.isCategorical() || size <= 0) { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts index 8613f9e1e946f..fbe643a401484 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts @@ -34,7 +34,7 @@ export async function createStyleFieldsHelper(fields: IField[]): Promise { const vectorStyle = new VectorStyle({ properties }, new MockSource()); const nextFields = [new MockField({ fieldName, dataType: 'number' })]; - const { hasChanges } = await vectorStyle.getDescriptorWithMissingStylePropsRemoved( + const { hasChanges } = await vectorStyle.getDescriptorWithUpdatedStyleProps( nextFields, mapColors ); @@ -82,7 +82,7 @@ describe('getDescriptorWithMissingStylePropsRemoved', () => { const { hasChanges, nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithMissingStylePropsRemoved(nextFields, mapColors); + } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); expect(hasChanges).toBe(true); expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ options: {}, @@ -104,7 +104,7 @@ describe('getDescriptorWithMissingStylePropsRemoved', () => { const { hasChanges, nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithMissingStylePropsRemoved(nextFields, mapColors); + } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); expect(hasChanges).toBe(true); expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ options: { @@ -129,7 +129,7 @@ describe('getDescriptorWithMissingStylePropsRemoved', () => { const { hasChanges, nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithMissingStylePropsRemoved(nextFields, mapColors); + } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); expect(hasChanges).toBe(true); expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ options: { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 5d360f5452d36..2ae9fd6461b2e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -6,7 +6,7 @@ import _ from 'lodash'; import React, { ReactElement } from 'react'; -import { Map as MbMap, FeatureIdentifier } from 'mapbox-gl'; +import { FeatureIdentifier, Map as MbMap } from 'mapbox-gl'; import { FeatureCollection } from 'geojson'; // @ts-expect-error import { VectorStyleEditor } from './components/vector_style_editor'; @@ -17,12 +17,12 @@ import { POLYGON_STYLES, } from './vector_style_defaults'; import { - GEO_JSON_TYPE, + DEFAULT_ICON, FIELD_ORIGIN, - STYLE_TYPE, - SOURCE_FORMATTERS_DATA_REQUEST_ID, + GEO_JSON_TYPE, LAYER_STYLE_TYPE, - DEFAULT_ICON, + SOURCE_FORMATTERS_DATA_REQUEST_ID, + STYLE_TYPE, VECTOR_SHAPE_TYPE, VECTOR_STYLES, } from '../../../../common/constants'; @@ -31,7 +31,7 @@ import { VectorIcon } from './components/legend/vector_icon'; import { VectorStyleLegend } from './components/legend/vector_style_legend'; import { isOnlySingleFeatureType } from './style_util'; import { StaticStyleProperty } from './properties/static_style_property'; -import { DynamicStyleProperty } from './properties/dynamic_style_property'; +import { DynamicStyleProperty, IDynamicStyleProperty } from './properties/dynamic_style_property'; import { DynamicSizeProperty } from './properties/dynamic_size_property'; import { StaticSizeProperty } from './properties/static_size_property'; import { StaticColorProperty } from './properties/static_color_property'; @@ -72,12 +72,12 @@ import { import { DataRequest } from '../../util/data_request'; import { IStyle } from '../style'; import { IStyleProperty } from './properties/style_property'; -import { IDynamicStyleProperty } from './properties/dynamic_style_property'; import { IField } from '../../fields/field'; import { IVectorLayer } from '../../layers/vector_layer/vector_layer'; import { IVectorSource } from '../../sources/vector_source'; import { ILayer } from '../../layers/layer'; -import { createStyleFieldsHelper } from './style_fields_helper'; +import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper'; +import { IESAggField } from '../../fields/agg'; const POINTS = [GEO_JSON_TYPE.POINT, GEO_JSON_TYPE.MULTI_POINT]; const LINES = [GEO_JSON_TYPE.LINE_STRING, GEO_JSON_TYPE.MULTI_LINE_STRING]; @@ -88,9 +88,10 @@ export interface IVectorStyle extends IStyle { getDynamicPropertiesArray(): Array>; getSourceFieldNames(): string[]; getStyleMeta(): StyleMeta; - getDescriptorWithMissingStylePropsRemoved( - nextFields: IField[], - mapColors: string[] + getDescriptorWithUpdatedStyleProps( + nextFields: IESAggField[], + mapColors: string[], + oldFields: IESAggField[] ): Promise<{ hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }>; pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): Promise; isTimeAware: () => boolean; @@ -175,6 +176,136 @@ export class VectorStyle implements IVectorStyle { return getDefaultProperties(mapColors); } + static async getDescriptorWithUpdatedFields( + currentFields: IESAggField[], + styleFieldsHelper: StyleFieldsHelper, + originalProperties: VectorStylePropertiesDescriptor, + previousFields: IESAggField[], + mapColors: string[], + isTimeAware: boolean, + dynamicStyleProperties: Array> + ) { + let hasChanges = false; + for (let i = 0; i < previousFields.length; i++) { + const previousField = previousFields[i]; + const currentField = currentFields[i]; + if (previousField.isEqual(currentField)) { + continue; + } + + for (let j = 0; j < dynamicStyleProperties.length; j++) { + const dynamicStyleProp = dynamicStyleProperties[j]; + + const newFieldDescriptor = dynamicStyleProp.rectifyFieldDescriptor(currentField, { + origin: previousField.getOrigin(), + name: previousField.getName(), + }); + + if (newFieldDescriptor !== null) { + const originalStyleProp = originalProperties[dynamicStyleProp.getStyleName()]; + originalStyleProp!.options!.field! = newFieldDescriptor; + hasChanges = true; + } + } + } + + return VectorStyle.getDescriptorWithDeletedStyleProps( + currentFields, + styleFieldsHelper, + originalProperties, + mapColors, + hasChanges, + isTimeAware + ); + + // return { + // hasChanges, + // nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, isTimeAware), + // }; + } + + static async getDescriptorWithDeletedStyleProps( + nextFields: IField[], + styleFieldsHelper: StyleFieldsHelper, + originalProperties: VectorStylePropertiesDescriptor, + mapColors: string[], + hasChanges: boolean, + isTimeAware: boolean + ) { + const updatedProperties = {} as VectorStylePropertiesDescriptor; + + const dynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter((key) => { + if (!originalProperties[key]) { + return false; + } + const propertyDescriptor = originalProperties[key]; + if ( + !propertyDescriptor || + !('type' in propertyDescriptor) || + propertyDescriptor.type !== STYLE_TYPE.DYNAMIC || + !propertyDescriptor.options + ) { + return false; + } + const dynamicOptions = propertyDescriptor.options as DynamicStylePropertyOptions; + return dynamicOptions.field && dynamicOptions.field.name; + }); + + dynamicProperties.forEach((key: VECTOR_STYLES) => { + // Convert dynamic styling to static stying when there are no style fields + const styleFields = styleFieldsHelper.getFieldsForStyle(key); + if (styleFields.length === 0) { + const staticProperties = getDefaultStaticProperties(mapColors); + updatedProperties[key] = staticProperties[key] as any; + return; + } + + const dynamicProperty = originalProperties[key]; + if (!dynamicProperty || !dynamicProperty.options) { + return; + } + const fieldName = (dynamicProperty.options as DynamicStylePropertyOptions).field!.name; + if (!fieldName) { + return; + } + + const matchingOrdinalField = nextFields.find((ordinalField) => { + return fieldName === ordinalField.getName(); + }); + + if (matchingOrdinalField) { + return; + } + + updatedProperties[key] = { + type: DynamicStyleProperty.type, + options: { + ...originalProperties[key]!.options, + }, + } as any; + // @ts-expect-error + delete updatedProperties[key].options.field; + }); + + if (Object.keys(updatedProperties).length !== 0) { + return { + hasChanges: true, + nextStyleDescriptor: VectorStyle.createDescriptor( + { + ...originalProperties, + ...updatedProperties, + }, + isTimeAware + ), + }; + } else { + return { + hasChanges, + nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, isTimeAware), + }; + } + } + constructor( descriptor: VectorStyleDescriptor | null, source: IVectorSource, @@ -243,6 +374,48 @@ export class VectorStyle implements IVectorStyle { ); } + /* + * Changes to source descriptor and join descriptor will impact style properties. + * For instance, a style property may be dynamically tied to the value of an ordinal field defined + * by a join or a metric aggregation. The metric aggregation or join may be edited or removed. + * When this happens, the style will be linked to a no-longer-existing ordinal field. + * This method provides a way for a style to clean itself and return a descriptor that unsets any dynamic + * properties that are tied to missing oridinal fields + * + * This method does not update its descriptor. It just returns a new descriptor that the caller + * can then use to update store state via dispatch. + */ + async getDescriptorWithUpdatedStyleProps( + nextFields: IESAggField[], + mapColors: string[], + oldFields: IESAggField[] + ) { + const styleFieldsHelper = await createStyleFieldsHelper(nextFields); + const originalProperties = this.getRawProperties(); + const dynamicStyleProperties = this.getAllStyleProperties().filter((p) => p.isDynamic()); + + if (oldFields.length === nextFields.length) { + return await VectorStyle.getDescriptorWithUpdatedFields( + nextFields, + styleFieldsHelper, + originalProperties, + oldFields, + mapColors, + this.isTimeAware(), + dynamicStyleProperties + ); + } else { + return await VectorStyle.getDescriptorWithDeletedStyleProps( + nextFields, + styleFieldsHelper, + originalProperties, + mapColors, + false, + this.isTimeAware() + ); + } + } + getType() { return LAYER_STYLE_TYPE.VECTOR; } @@ -314,94 +487,6 @@ export class VectorStyle implements IVectorStyle { ); } - /* - * Changes to source descriptor and join descriptor will impact style properties. - * For instance, a style property may be dynamically tied to the value of an ordinal field defined - * by a join or a metric aggregation. The metric aggregation or join may be edited or removed. - * When this happens, the style will be linked to a no-longer-existing ordinal field. - * This method provides a way for a style to clean itself and return a descriptor that unsets any dynamic - * properties that are tied to missing oridinal fields - * - * This method does not update its descriptor. It just returns a new descriptor that the caller - * can then use to update store state via dispatch. - */ - async getDescriptorWithMissingStylePropsRemoved(nextFields: IField[], mapColors: string[]) { - const styleFieldsHelper = await createStyleFieldsHelper(nextFields); - const originalProperties = this.getRawProperties(); - const updatedProperties = {} as VectorStylePropertiesDescriptor; - - const dynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter((key) => { - if (!originalProperties[key]) { - return false; - } - const propertyDescriptor = originalProperties[key]; - if ( - !propertyDescriptor || - !('type' in propertyDescriptor) || - propertyDescriptor.type !== STYLE_TYPE.DYNAMIC || - !propertyDescriptor.options - ) { - return false; - } - const dynamicOptions = propertyDescriptor.options as DynamicStylePropertyOptions; - return dynamicOptions.field && dynamicOptions.field.name; - }); - - dynamicProperties.forEach((key: VECTOR_STYLES) => { - // Convert dynamic styling to static stying when there are no style fields - const styleFields = styleFieldsHelper.getFieldsForStyle(key); - if (styleFields.length === 0) { - const staticProperties = getDefaultStaticProperties(mapColors); - updatedProperties[key] = staticProperties[key] as any; - return; - } - - const dynamicProperty = originalProperties[key]; - if (!dynamicProperty || !dynamicProperty.options) { - return; - } - const fieldName = (dynamicProperty.options as DynamicStylePropertyOptions).field!.name; - if (!fieldName) { - return; - } - - const matchingOrdinalField = nextFields.find((ordinalField) => { - return fieldName === ordinalField.getName(); - }); - - if (matchingOrdinalField) { - return; - } - - updatedProperties[key] = { - type: DynamicStyleProperty.type, - options: { - ...originalProperties[key]!.options, - }, - } as any; - // @ts-expect-error - delete updatedProperties[key].options.field; - }); - - if (Object.keys(updatedProperties).length === 0) { - return { - hasChanges: false, - nextStyleDescriptor: { ...this._descriptor }, - }; - } - - return { - hasChanges: true, - nextStyleDescriptor: VectorStyle.createDescriptor( - { - ...originalProperties, - ...updatedProperties, - }, - this.isTimeAware() - ), - }; - } - async pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest) { const features = _.get(sourceDataRequest.getData(), 'features', []); diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index f6282be26b40c..2599e8269d0e1 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -143,7 +143,7 @@ export const getSelectedLayerId = ({ map }: MapStoreState): string | null => { return !map.selectedLayerId || !map.layerList ? null : map.selectedLayerId; }; -export const getLayerListRaw = ({ map }: MapStoreState): LayerDescriptor[] => +export const getLayerListRaw = ({ map }: MapStoreState = {}): LayerDescriptor[] => map.layerList ? map.layerList : []; export const getWaitingForMapReadyLayerListRaw = ({ map }: MapStoreState): LayerDescriptor[] => From 47560f92422e3f1bd3fff3d51b3f896e31e3adff Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 18 Nov 2020 09:31:41 -0500 Subject: [PATCH 21/62] some type fixes --- .../plugins/maps/public/actions/layer_actions.ts | 14 ++++++-------- .../fields/agg/top_term_percentage_field.ts | 4 ++++ .../vector/properties/dynamic_style_property.tsx | 7 +++++++ .../public/classes/styles/vector/vector_style.tsx | 9 +++++++-- .../plugins/maps/public/selectors/map_selectors.ts | 2 +- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 71a914668009c..73429f9e5cf9c 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -45,9 +45,6 @@ import { IVectorLayer } from '../classes/layers/vector_layer/vector_layer'; import { LAYER_STYLE_TYPE, LAYER_TYPE } from '../../common/constants'; import { IVectorStyle } from '../classes/styles/vector/vector_style'; import { notifyLicensedFeatureUsage } from '../licensed_features'; -import { IVectorSource } from '../classes/sources/vector_source'; -import { IESSource } from '../classes/sources/es_source'; -import { IESAggSource } from '../classes/sources/es_agg_source'; import { IESAggField } from '../classes/fields/agg'; export function trackCurrentLayerState(layerId: string) { @@ -300,7 +297,7 @@ export function updateSourceProp( if (newLayerType) { dispatch(updateLayerType(layerId, newLayerType)); } - await dispatch(updateStyleProperties(layerId, oldFields)); + await dispatch(updateStyleProperties(layerId, oldFields as IESAggField[])); dispatch(syncDataForLayerId(layerId)); } else { dispatch({ @@ -312,7 +309,7 @@ export function updateSourceProp( if (newLayerType) { dispatch(updateLayerType(layerId, newLayerType)); } - await dispatch(updateStyleProperties(layerId)); + // await dispatch(updateStyleProperties(layerId)); dispatch(syncDataForLayerId(layerId)); } }; @@ -445,7 +442,7 @@ function removeLayerFromLayerList(layerId: string) { }; } -export function updateStyleProperties(layerId: string, oldFields: IESAggField[]) { +export function updateStyleProperties(layerId: string, previousFields: IESAggField[]) { return async ( dispatch: ThunkDispatch, getState: () => MapStoreState @@ -467,7 +464,7 @@ export function updateStyleProperties(layerId: string, oldFields: IESAggField[]) } = await (style as IVectorStyle).getDescriptorWithUpdatedStyleProps( nextFields as IESAggField[], getMapColors(getState()), - oldFields + previousFields ); if (hasChanges && nextStyleDescriptor) { dispatch(updateLayerStyle(layerId, nextStyleDescriptor)); @@ -515,7 +512,8 @@ export function setJoinsForLayer(layer: ILayer, joins: JoinDescriptor[]) { joins, }); - await dispatch(updateStyleProperties(layer.getId())); + const previousFields = await (layer as IVectorLayer).getFields(); + await dispatch(updateStyleProperties(layer.getId(), previousFields)); dispatch(syncDataForLayerId(layer.getId())); }; } diff --git a/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts index e3d62afaca921..cc8e3b4675308 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/top_term_percentage_field.ts @@ -83,4 +83,8 @@ export class TopTermPercentageField implements IESAggField { canReadFromGeoJson(): boolean { return this._canReadFromGeoJson; } + + isEqual(field: IESAggField) { + return field.getName() === this.getName(); + } } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index bcd72f8beed7c..b438eaf20ec45 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -18,6 +18,7 @@ import { VECTOR_STYLES, RawValue, FieldFormatter, + TOP_TERM_PERCENTAGE_SUFFIX, } from '../../../../../common/constants'; import { OrdinalFieldMetaPopover } from '../components/field_meta/ordinal_field_meta_popover'; import { CategoricalFieldMetaPopover } from '../components/field_meta/categorical_field_meta_popover'; @@ -251,6 +252,12 @@ export class DynamicStyleProperty previousFieldDescriptor: StylePropertyField ): StylePropertyField | null { // Todo: individual style property classes would need to override this with "smart" behavior + + if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { + // Don't support auto-switching for top-term-percentages + return null; + } + return { origin: previousFieldDescriptor.origin, name: currentField.getName(), diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 2ae9fd6461b2e..10abdbaae790c 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -183,8 +183,10 @@ export class VectorStyle implements IVectorStyle { previousFields: IESAggField[], mapColors: string[], isTimeAware: boolean, - dynamicStyleProperties: Array> + dynamicStyleProperties: Array>> ) { + // Try and correct metrics first. + let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; @@ -392,9 +394,12 @@ export class VectorStyle implements IVectorStyle { ) { const styleFieldsHelper = await createStyleFieldsHelper(nextFields); const originalProperties = this.getRawProperties(); - const dynamicStyleProperties = this.getAllStyleProperties().filter((p) => p.isDynamic()); + const dynamicStyleProperties: DynamicStyleProperty = this.getAllStyleProperties().filter((p) => + p.isDynamic() + ) as DynamicStyleProperty; if (oldFields.length === nextFields.length) { + // Change in metrics return await VectorStyle.getDescriptorWithUpdatedFields( nextFields, styleFieldsHelper, diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 2599e8269d0e1..f6282be26b40c 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -143,7 +143,7 @@ export const getSelectedLayerId = ({ map }: MapStoreState): string | null => { return !map.selectedLayerId || !map.layerList ? null : map.selectedLayerId; }; -export const getLayerListRaw = ({ map }: MapStoreState = {}): LayerDescriptor[] => +export const getLayerListRaw = ({ map }: MapStoreState): LayerDescriptor[] => map.layerList ? map.layerList : []; export const getWaitingForMapReadyLayerListRaw = ({ map }: MapStoreState): LayerDescriptor[] => From 71e49df11c68664d1a6b49607afabcbcc4e4a54c Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 18 Nov 2020 13:49:49 -0500 Subject: [PATCH 22/62] add type check --- .../VisitorBreakdownMap/useLayerList.ts | 1 + .../properties/dynamic_style_property.tsx | 6 ++-- .../styles/vector/style_fields_helper.ts | 5 +++ .../classes/styles/vector/vector_style.tsx | 34 +++++++++---------- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts index a1cdf7bb646e5..0c922ec361ccd 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts @@ -100,6 +100,7 @@ export function useLayerList() { visible: true, style: { type: 'TILE' }, type: 'VECTOR_TILE', + areLabelsOnTop: true, }; ES_TERM_SOURCE_COUNTRY.whereQuery = getWhereQuery(serviceName!); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index b438eaf20ec45..59e918284a5f2 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -54,7 +54,7 @@ export interface IDynamicStyleProperty extends IStyleProperty { rectifyFieldDescriptor( currentField: IESAggField, previousFieldDescriptor: StylePropertyField - ): StylePropertyField | null; + ): StylePropertyField | undefined; enrichGeoJsonAndMbFeatureState( featureCollection: FeatureCollection, mbMap: MbMap, @@ -250,12 +250,12 @@ export class DynamicStyleProperty rectifyFieldDescriptor( currentField: IESAggField, previousFieldDescriptor: StylePropertyField - ): StylePropertyField | null { + ): StylePropertyField | undefined { // Todo: individual style property classes would need to override this with "smart" behavior if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { // Don't support auto-switching for top-term-percentages - return null; + return; } return { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts index fbe643a401484..c727e4a5d81f3 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts @@ -69,6 +69,11 @@ export class StyleFieldsHelper { this._ordinalFields = ordinalFields; } + isFieldDataTypeCompatibleWithStyleType(field: IField, styleName: VECTOR_STYLES): boolean { + const fieldList = this.getFieldsForStyle(styleName); + return !!fieldList.find((styleField) => field.getName() === styleField.name); + } + getFieldsForStyle(styleName: VECTOR_STYLES): StyleField[] { switch (styleName) { case VECTOR_STYLES.ICON_ORIENTATION: diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 10abdbaae790c..90ad505801a0e 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -185,8 +185,6 @@ export class VectorStyle implements IVectorStyle { isTimeAware: boolean, dynamicStyleProperties: Array>> ) { - // Try and correct metrics first. - let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; @@ -197,17 +195,24 @@ export class VectorStyle implements IVectorStyle { for (let j = 0; j < dynamicStyleProperties.length; j++) { const dynamicStyleProp = dynamicStyleProperties[j]; - - const newFieldDescriptor = dynamicStyleProp.rectifyFieldDescriptor(currentField, { - origin: previousField.getOrigin(), - name: previousField.getName(), - }); - - if (newFieldDescriptor !== null) { - const originalStyleProp = originalProperties[dynamicStyleProp.getStyleName()]; - originalStyleProp!.options!.field! = newFieldDescriptor; - hasChanges = true; + let newFieldDescriptor: StylePropertyField; + const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( + currentField, + dynamicStyleProp.getStyleName() + ); + if (isFieldDataTypeCompatible) { + newFieldDescriptor = dynamicStyleProp.rectifyFieldDescriptor(currentField, { + origin: previousField.getOrigin(), + name: previousField.getName(), + }); + + if (newFieldDescriptor) { + hasChanges = true; + } } + + const originalStyleProp = originalProperties[dynamicStyleProp.getStyleName()]; + originalStyleProp!.options!.field = newFieldDescriptor; } } @@ -219,11 +224,6 @@ export class VectorStyle implements IVectorStyle { hasChanges, isTimeAware ); - - // return { - // hasChanges, - // nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, isTimeAware), - // }; } static async getDescriptorWithDeletedStyleProps( From b7d8bbdb3d1f9928f7dbfced501639bfaa4a90d4 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 18 Nov 2020 14:02:11 -0500 Subject: [PATCH 23/62] only take into account invalid dynamic fields --- .../classes/styles/vector/vector_style.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 90ad505801a0e..450b8cfeca3e4 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -185,6 +185,16 @@ export class VectorStyle implements IVectorStyle { isTimeAware: boolean, dynamicStyleProperties: Array>> ) { + // remove style-props that have a valid field config + // theoretically possible with re-order, but not in practice + const invalidStyleProps = dynamicStyleProperties.filter((styleProp) => { + const matchingField = currentFields.find((field) => { + const f = styleProp.getField(); + return f && field.isEqual(f); + }); + return !matchingField; + }); + let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; @@ -193,15 +203,14 @@ export class VectorStyle implements IVectorStyle { continue; } - for (let j = 0; j < dynamicStyleProperties.length; j++) { - const dynamicStyleProp = dynamicStyleProperties[j]; + invalidStyleProps.forEach((invalidStyleProp) => { let newFieldDescriptor: StylePropertyField; const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( currentField, - dynamicStyleProp.getStyleName() + invalidStyleProp.getStyleName() ); if (isFieldDataTypeCompatible) { - newFieldDescriptor = dynamicStyleProp.rectifyFieldDescriptor(currentField, { + newFieldDescriptor = invalidStyleProp.rectifyFieldDescriptor(currentField, { origin: previousField.getOrigin(), name: previousField.getName(), }); @@ -211,9 +220,9 @@ export class VectorStyle implements IVectorStyle { } } - const originalStyleProp = originalProperties[dynamicStyleProp.getStyleName()]; + const originalStyleProp = originalProperties[invalidStyleProp.getStyleName()]; originalStyleProp!.options!.field = newFieldDescriptor; - } + }); } return VectorStyle.getDescriptorWithDeletedStyleProps( From c507a778bcb670d824595ab5e5d5255c9d7147d5 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 18 Nov 2020 17:10:36 -0500 Subject: [PATCH 24/62] tmp debug --- .../maps/public/actions/layer_actions.ts | 1 + .../properties/dynamic_color_property.tsx | 6 +++- .../properties/dynamic_style_property.tsx | 9 +++--- .../classes/styles/vector/vector_style.tsx | 32 ++++++++++++------- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 73429f9e5cf9c..37ee074f92077 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -447,6 +447,7 @@ export function updateStyleProperties(layerId: string, previousFields: IESAggFie dispatch: ThunkDispatch, getState: () => MapStoreState ) => { + console.log('update style props', layerId, previousFields); const targetLayer = getLayerById(layerId, getState()); if (!targetLayer || !('getFields' in targetLayer)) { return; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index faecf51d4ced5..c3ee68d8f78e5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -17,7 +17,11 @@ import { // @ts-expect-error } from '../components/color/color_stops_utils'; import { BreakedLegend } from '../components/legend/breaked_legend'; -import { ColorDynamicOptions, OrdinalColorStop } from '../../../../../common/descriptor_types'; +import { + ColorDynamicOptions, + OrdinalColorStop, + StylePropertyField, +} from '../../../../../common/descriptor_types'; import { LegendProps } from './style_property'; const EMPTY_STOPS = { stops: [], defaultColor: null }; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index 59e918284a5f2..c4798d97f8749 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -54,7 +54,7 @@ export interface IDynamicStyleProperty extends IStyleProperty { rectifyFieldDescriptor( currentField: IESAggField, previousFieldDescriptor: StylePropertyField - ): StylePropertyField | undefined; + ): Promise; enrichGeoJsonAndMbFeatureState( featureCollection: FeatureCollection, mbMap: MbMap, @@ -247,17 +247,18 @@ export class DynamicStyleProperty } as RangeFieldMeta); } - rectifyFieldDescriptor( + async rectifyFieldDescriptor( currentField: IESAggField, previousFieldDescriptor: StylePropertyField - ): StylePropertyField | undefined { + ): Promise { // Todo: individual style property classes would need to override this with "smart" behavior - if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { // Don't support auto-switching for top-term-percentages + console.log('cant', previousFieldDescriptor.name); return; } + console.log('recitf') return { origin: previousFieldDescriptor.origin, name: currentField.getName(), diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 450b8cfeca3e4..a84ca17606157 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -195,6 +195,7 @@ export class VectorStyle implements IVectorStyle { return !matchingField; }); + console.log('inv', invalidStyleProps, previousFields, currentFields); let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; @@ -203,18 +204,24 @@ export class VectorStyle implements IVectorStyle { continue; } - invalidStyleProps.forEach((invalidStyleProp) => { - let newFieldDescriptor: StylePropertyField; + // invalidStyleProps.forEach(async (invalidStyleProp) => { + for (let j = 0; j < invalidStyleProps.length; j++) { + const invalidStyleProp = invalidStyleProps[j]; + let newFieldDescriptor: StylePropertyField | undefined; + + console.log('----------is com', invalidStyleProp, currentField, previousField); const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( currentField, invalidStyleProp.getStyleName() ); + console.log('is compatible', isFieldDataTypeCompatible); if (isFieldDataTypeCompatible) { - newFieldDescriptor = invalidStyleProp.rectifyFieldDescriptor(currentField, { + newFieldDescriptor = await invalidStyleProp.rectifyFieldDescriptor(currentField, { origin: previousField.getOrigin(), name: previousField.getName(), }); + console.log('nw', newFieldDescriptor); if (newFieldDescriptor) { hasChanges = true; } @@ -222,9 +229,11 @@ export class VectorStyle implements IVectorStyle { const originalStyleProp = originalProperties[invalidStyleProp.getStyleName()]; originalStyleProp!.options!.field = newFieldDescriptor; - }); + } + // }); } + // Still run correction to revert invalid props to static styling, if necessary return VectorStyle.getDescriptorWithDeletedStyleProps( currentFields, styleFieldsHelper, @@ -397,30 +406,31 @@ export class VectorStyle implements IVectorStyle { * can then use to update store state via dispatch. */ async getDescriptorWithUpdatedStyleProps( - nextFields: IESAggField[], + currentFields: IESAggField[], mapColors: string[], - oldFields: IESAggField[] + previousFields: IESAggField[] ) { - const styleFieldsHelper = await createStyleFieldsHelper(nextFields); + const styleFieldsHelper = await createStyleFieldsHelper(currentFields); const originalProperties = this.getRawProperties(); const dynamicStyleProperties: DynamicStyleProperty = this.getAllStyleProperties().filter((p) => p.isDynamic() ) as DynamicStyleProperty; - if (oldFields.length === nextFields.length) { + console.log(previousFields, currentFields); + if (previousFields.length === currentFields.length) { // Change in metrics return await VectorStyle.getDescriptorWithUpdatedFields( - nextFields, + currentFields, styleFieldsHelper, originalProperties, - oldFields, + previousFields, mapColors, this.isTimeAware(), dynamicStyleProperties ); } else { return await VectorStyle.getDescriptorWithDeletedStyleProps( - nextFields, + currentFields, styleFieldsHelper, originalProperties, mapColors, From ffad517b3ba4a57084d8572576da8fe881a81553 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Fri, 20 Nov 2020 16:00:05 -0500 Subject: [PATCH 25/62] ts type fixes --- .../maps/public/actions/layer_actions.ts | 5 ++- .../classes/fields/agg/agg_field_types.ts | 1 - .../maps/public/classes/fields/field.ts | 5 +++ .../properties/dynamic_color_property.tsx | 6 +-- .../classes/styles/vector/vector_style.tsx | 41 ++++++++++--------- 5 files changed, 31 insertions(+), 27 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 73429f9e5cf9c..f2eb6c9a7782b 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -46,6 +46,7 @@ import { LAYER_STYLE_TYPE, LAYER_TYPE } from '../../common/constants'; import { IVectorStyle } from '../classes/styles/vector/vector_style'; import { notifyLicensedFeatureUsage } from '../licensed_features'; import { IESAggField } from '../classes/fields/agg'; +import { IField } from '../classes/fields/field'; export function trackCurrentLayerState(layerId: string) { return { @@ -442,7 +443,7 @@ function removeLayerFromLayerList(layerId: string) { }; } -export function updateStyleProperties(layerId: string, previousFields: IESAggField[]) { +export function updateStyleProperties(layerId: string, previousFields: IField[]) { return async ( dispatch: ThunkDispatch, getState: () => MapStoreState @@ -462,7 +463,7 @@ export function updateStyleProperties(layerId: string, previousFields: IESAggFie hasChanges, nextStyleDescriptor, } = await (style as IVectorStyle).getDescriptorWithUpdatedStyleProps( - nextFields as IESAggField[], + nextFields, getMapColors(getState()), previousFields ); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts index 8ed297a13efa3..74f03a3f31909 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/agg_field_types.ts @@ -12,7 +12,6 @@ import { FIELD_ORIGIN } from '../../../../common/constants'; export interface IESAggField extends IField { getValueAggDsl(indexPattern: IndexPattern): unknown | null; getBucketCount(): number; - isEqual(field: IESAggField): boolean; } export interface CountAggFieldParams { diff --git a/x-pack/plugins/maps/public/classes/fields/field.ts b/x-pack/plugins/maps/public/classes/fields/field.ts index 658c2bba87847..9cb7debd320a1 100644 --- a/x-pack/plugins/maps/public/classes/fields/field.ts +++ b/x-pack/plugins/maps/public/classes/fields/field.ts @@ -32,6 +32,7 @@ export interface IField { supportsFieldMeta(): boolean; canReadFromGeoJson(): boolean; + isEqual(field: IField): boolean; } export class AbstractField implements IField { @@ -99,4 +100,8 @@ export class AbstractField implements IField { canReadFromGeoJson(): boolean { return true; } + + isEqual(field: IField) { + return this._origin === field.getOrigin() && this._fieldName === field.getName(); + } } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index c3ee68d8f78e5..faecf51d4ced5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -17,11 +17,7 @@ import { // @ts-expect-error } from '../components/color/color_stops_utils'; import { BreakedLegend } from '../components/legend/breaked_legend'; -import { - ColorDynamicOptions, - OrdinalColorStop, - StylePropertyField, -} from '../../../../../common/descriptor_types'; +import { ColorDynamicOptions, OrdinalColorStop } from '../../../../../common/descriptor_types'; import { LegendProps } from './style_property'; const EMPTY_STOPS = { stops: [], defaultColor: null }; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 3ab8ab0948f52..401582942e40c 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -82,9 +82,9 @@ export interface IVectorStyle extends IStyle { getSourceFieldNames(): string[]; getStyleMeta(): StyleMeta; getDescriptorWithUpdatedStyleProps( - nextFields: IESAggField[], + nextFields: IField[], mapColors: string[], - oldFields: IESAggField[] + oldFields: IField[] ): Promise<{ hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }>; pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): Promise; isTimeAware: () => boolean; @@ -173,20 +173,20 @@ export class VectorStyle implements IVectorStyle { } static async getDescriptorWithUpdatedFields( - currentFields: IESAggField[], + currentFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, - previousFields: IESAggField[], + previousFields: IField[], mapColors: string[], isTimeAware: boolean, - dynamicStyleProperties: Array>> + dynamicStyleProperties: Array> ) { // remove style-props that have a valid field config // theoretically possible with re-order, but not in practice const invalidStyleProps = dynamicStyleProperties.filter((styleProp) => { const matchingField = currentFields.find((field) => { const f = styleProp.getField(); - return f && field.isEqual(f); + return f && f.isEqual(f); }); return !matchingField; }); @@ -209,10 +209,13 @@ export class VectorStyle implements IVectorStyle { invalidStyleProp.getStyleName() ); if (isFieldDataTypeCompatible) { - newFieldDescriptor = await invalidStyleProp.rectifyFieldDescriptor(currentField, { - origin: previousField.getOrigin(), - name: previousField.getName(), - }); + newFieldDescriptor = await invalidStyleProp.rectifyFieldDescriptor( + currentField as IESAggField, + { + origin: previousField.getOrigin(), + name: previousField.getName(), + } + ); if (newFieldDescriptor) { hasChanges = true; @@ -220,8 +223,10 @@ export class VectorStyle implements IVectorStyle { } } - const originalStyleProp = originalProperties[invalidStyleProp.getStyleName()]; - originalStyleProp!.options!.field = newFieldDescriptor; + if (invalidStyleProp.getStyleName() !== VECTOR_STYLES.SYMBOLIZE_AS) { + const originalStyleProp = originalProperties[invalidStyleProp.getStyleName()]; + originalStyleProp!.options!.field = newFieldDescriptor; + } } // }); } @@ -399,15 +404,13 @@ export class VectorStyle implements IVectorStyle { * can then use to update store state via dispatch. */ async getDescriptorWithUpdatedStyleProps( - currentFields: IESAggField[], + currentFields: IField[], mapColors: string[], - previousFields: IESAggField[] + previousFields: IField[] ) { const styleFieldsHelper = await createStyleFieldsHelper(currentFields); const originalProperties = this.getRawProperties(); - const dynamicStyleProperties: DynamicStyleProperty = this.getAllStyleProperties().filter((p) => - p.isDynamic() - ) as DynamicStyleProperty; + const dynamicStyleProperties = this.getDynamicPropertiesArray(); if (previousFields.length === currentFields.length) { // Change in metrics @@ -436,7 +439,7 @@ export class VectorStyle implements IVectorStyle { return LAYER_STYLE_TYPE.VECTOR; } - getAllStyleProperties() { + getAllStyleProperties(): Array> { return [ this._symbolizeAsStyleProperty, this._iconStyleProperty, @@ -587,7 +590,7 @@ export class VectorStyle implements IVectorStyle { return this._descriptor.properties || {}; } - getDynamicPropertiesArray() { + getDynamicPropertiesArray(): Array> { const styleProperties = this.getAllStyleProperties(); return styleProperties.filter( (styleProperty) => styleProperty.isDynamic() && styleProperty.isComplete() From e00204778d35a2741bb375d724c94520f275ea53 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 23 Nov 2020 09:48:20 -0500 Subject: [PATCH 26/62] retype --- .../classes/styles/vector/vector_style.tsx | 100 ++++++++++-------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 401582942e40c..f54089ff170de 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -172,24 +172,21 @@ export class VectorStyle implements IVectorStyle { return getDefaultStaticProperties(mapColors); } - static async getDescriptorWithUpdatedFields( + static async updateFieldsInDescriptor( currentFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, previousFields: IField[], mapColors: string[], isTimeAware: boolean, - dynamicStyleProperties: Array> + dynamicProperties: Array> ) { - // remove style-props that have a valid field config - // theoretically possible with re-order, but not in practice - const invalidStyleProps = dynamicStyleProperties.filter((styleProp) => { - const matchingField = currentFields.find((field) => { - const f = styleProp.getField(); - return f && f.isEqual(f); - }); - return !matchingField; - }); + const invalidDynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter( + (key) => { + const dynamicOptions = getDynamicOptions(originalProperties, key); + return dynamicOptions && (!dynamicOptions.field || !dynamicOptions.field.name); + } + ); let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { @@ -199,17 +196,23 @@ export class VectorStyle implements IVectorStyle { continue; } - // invalidStyleProps.forEach(async (invalidStyleProp) => { - for (let j = 0; j < invalidStyleProps.length; j++) { - const invalidStyleProp = invalidStyleProps[j]; + // Check if the updated field can be assigned to any of the broken style-properties. + for (let j = 0; j < invalidDynamicProperties.length; j++) { + const dynamicProperty = dynamicProperties.find( + (d) => d.getStyleName() === invalidDynamicProperties[j] + ); + + if (!dynamicProperty) { + continue; + } let newFieldDescriptor: StylePropertyField | undefined; const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( currentField, - invalidStyleProp.getStyleName() + dynamicProperty.getStyleName() ); if (isFieldDataTypeCompatible) { - newFieldDescriptor = await invalidStyleProp.rectifyFieldDescriptor( + newFieldDescriptor = await dynamicProperty.rectifyFieldDescriptor( currentField as IESAggField, { origin: previousField.getOrigin(), @@ -219,20 +222,17 @@ export class VectorStyle implements IVectorStyle { if (newFieldDescriptor) { hasChanges = true; - invalidStyleProps.splice(j, 1); + invalidDynamicProperties.splice(j, 1); } } - if (invalidStyleProp.getStyleName() !== VECTOR_STYLES.SYMBOLIZE_AS) { - const originalStyleProp = originalProperties[invalidStyleProp.getStyleName()]; - originalStyleProp!.options!.field = newFieldDescriptor; - } + const originalStyleProp = originalProperties[dynamicProperty.getStyleName()]; + originalStyleProp!.options!.field = newFieldDescriptor; } - // }); } - // Still run correction to revert invalid props to static styling, if necessary - return VectorStyle.getDescriptorWithDeletedStyleProps( + // Revert left-over invalid props to static styling, if necessary + return VectorStyle.deleteFieldsFromDescriptorAndUpdateStyling( currentFields, styleFieldsHelper, originalProperties, @@ -242,7 +242,7 @@ export class VectorStyle implements IVectorStyle { ); } - static async getDescriptorWithDeletedStyleProps( + static async deleteFieldsFromDescriptorAndUpdateStyling( nextFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, @@ -253,20 +253,8 @@ export class VectorStyle implements IVectorStyle { const updatedProperties = {} as VectorStylePropertiesDescriptor; const dynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter((key) => { - if (!originalProperties[key]) { - return false; - } - const propertyDescriptor = originalProperties[key]; - if ( - !propertyDescriptor || - !('type' in propertyDescriptor) || - propertyDescriptor.type !== STYLE_TYPE.DYNAMIC || - !propertyDescriptor.options - ) { - return false; - } - const dynamicOptions = propertyDescriptor.options as DynamicStylePropertyOptions; - return dynamicOptions.field && dynamicOptions.field.name; + const dynamicOptions = getDynamicOptions(originalProperties, key); + return dynamicOptions && dynamicOptions.field && dynamicOptions.field.name; }); dynamicProperties.forEach((key: VECTOR_STYLES) => { @@ -301,8 +289,10 @@ export class VectorStyle implements IVectorStyle { ...originalProperties[key]!.options, }, } as any; - // @ts-expect-error - delete updatedProperties[key].options.field; + + if ('field' in updatedProperties[key].options) { + delete updatedProperties[key].options.field; + } }); if (Object.keys(updatedProperties).length !== 0) { @@ -410,21 +400,20 @@ export class VectorStyle implements IVectorStyle { ) { const styleFieldsHelper = await createStyleFieldsHelper(currentFields); const originalProperties = this.getRawProperties(); - const dynamicStyleProperties = this.getDynamicPropertiesArray(); if (previousFields.length === currentFields.length) { - // Change in metrics - return await VectorStyle.getDescriptorWithUpdatedFields( + return await VectorStyle.updateFieldsInDescriptor( currentFields, styleFieldsHelper, originalProperties, previousFields, mapColors, this.isTimeAware(), - dynamicStyleProperties + this.getAllStyleProperties().filter((f) => f.isDynamic()) ); } else { - return await VectorStyle.getDescriptorWithDeletedStyleProps( + // Metrics got added and/or deleted + return await VectorStyle.deleteFieldsFromDescriptorAndUpdateStyling( currentFields, styleFieldsHelper, originalProperties, @@ -990,3 +979,22 @@ export class VectorStyle implements IVectorStyle { } } } + +function getDynamicOptions( + originalProperties, + key: VECTOR_STYLES +): DynamicStylePropertyOptions | null { + if (!originalProperties[key]) { + return null; + } + const propertyDescriptor = originalProperties[key]; + if ( + !propertyDescriptor || + !('type' in propertyDescriptor) || + propertyDescriptor.type !== STYLE_TYPE.DYNAMIC || + !propertyDescriptor.options + ) { + return null; + } + return propertyDescriptor.options as DynamicStylePropertyOptions; +} From 9590abd20a5b68335c3ffbfe772d6d6e780031ad Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 23 Nov 2020 14:36:48 -0500 Subject: [PATCH 27/62] fix field-lookup after refactor --- .../maps/public/classes/styles/vector/vector_style.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index f54089ff170de..2d25e3bd912d4 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -184,7 +184,14 @@ export class VectorStyle implements IVectorStyle { const invalidDynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter( (key) => { const dynamicOptions = getDynamicOptions(originalProperties, key); - return dynamicOptions && (!dynamicOptions.field || !dynamicOptions.field.name); + if (!dynamicOptions || !dynamicOptions.field || !dynamicOptions.field.name) { + return; + } + + const matchingField = currentFields.find((field) => { + return dynamicOptions.field.name === field.getName(); + }); + return !matchingField; } ); @@ -223,6 +230,7 @@ export class VectorStyle implements IVectorStyle { if (newFieldDescriptor) { hasChanges = true; invalidDynamicProperties.splice(j, 1); + j--; } } From e1e7ea0b8e7a5f376c801ffada68037ce6c112c6 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 23 Nov 2020 15:41:01 -0500 Subject: [PATCH 28/62] type fixes --- .../maps/public/actions/layer_actions.ts | 4 +- .../classes/styles/vector/vector_style.tsx | 87 +++++++++---------- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index f2eb6c9a7782b..ba8aab9fb8e49 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -464,8 +464,8 @@ export function updateStyleProperties(layerId: string, previousFields: IField[]) nextStyleDescriptor, } = await (style as IVectorStyle).getDescriptorWithUpdatedStyleProps( nextFields, - getMapColors(getState()), - previousFields + previousFields, + getMapColors(getState()) ); if (hasChanges && nextStyleDescriptor) { dispatch(updateLayerStyle(layerId, nextStyleDescriptor)); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 2d25e3bd912d4..64ad4db5adeb5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -83,8 +83,8 @@ export interface IVectorStyle extends IStyle { getStyleMeta(): StyleMeta; getDescriptorWithUpdatedStyleProps( nextFields: IField[], - mapColors: string[], - oldFields: IField[] + oldFields: IField[], + mapColors: string[] ): Promise<{ hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }>; pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): Promise; isTimeAware: () => boolean; @@ -172,14 +172,12 @@ export class VectorStyle implements IVectorStyle { return getDefaultStaticProperties(mapColors); } - static async updateFieldsInDescriptor( + async _updateFieldsInDescriptor( currentFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, previousFields: IField[], - mapColors: string[], - isTimeAware: boolean, - dynamicProperties: Array> + mapColors: string[] ) { const invalidDynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter( (key) => { @@ -189,7 +187,9 @@ export class VectorStyle implements IVectorStyle { } const matchingField = currentFields.find((field) => { - return dynamicOptions.field.name === field.getName(); + return ( + dynamicOptions && dynamicOptions.field && dynamicOptions.field.name === field.getName() + ); }); return !matchingField; } @@ -205,15 +205,15 @@ export class VectorStyle implements IVectorStyle { // Check if the updated field can be assigned to any of the broken style-properties. for (let j = 0; j < invalidDynamicProperties.length; j++) { - const dynamicProperty = dynamicProperties.find( + const dynamicProperty: IDynamicStyleProperty = this.getAllStyleProperties().find( (d) => d.getStyleName() === invalidDynamicProperties[j] - ); + ) as IDynamicStyleProperty; if (!dynamicProperty) { continue; } - let newFieldDescriptor: StylePropertyField | undefined; + let newFieldDescriptor: StylePropertyField | undefined; const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( currentField, dynamicProperty.getStyleName() @@ -234,29 +234,27 @@ export class VectorStyle implements IVectorStyle { } } - const originalStyleProp = originalProperties[dynamicProperty.getStyleName()]; - originalStyleProp!.options!.field = newFieldDescriptor; + (originalProperties[dynamicProperty.getStyleName()]! + .options! as DynamicStylePropertyOptions).field = newFieldDescriptor; } } // Revert left-over invalid props to static styling, if necessary - return VectorStyle.deleteFieldsFromDescriptorAndUpdateStyling( + return this._deleteFieldsFromDescriptorAndUpdateStyling( currentFields, styleFieldsHelper, originalProperties, mapColors, - hasChanges, - isTimeAware + hasChanges ); } - static async deleteFieldsFromDescriptorAndUpdateStyling( + async _deleteFieldsFromDescriptorAndUpdateStyling( nextFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, mapColors: string[], - hasChanges: boolean, - isTimeAware: boolean + hasChanges: boolean ) { const updatedProperties = {} as VectorStylePropertiesDescriptor; @@ -299,7 +297,7 @@ export class VectorStyle implements IVectorStyle { } as any; if ('field' in updatedProperties[key].options) { - delete updatedProperties[key].options.field; + delete (updatedProperties[key].options as DynamicStylePropertyOptions).field; } }); @@ -311,13 +309,13 @@ export class VectorStyle implements IVectorStyle { ...originalProperties, ...updatedProperties, }, - isTimeAware + this.isTimeAware() ), }; } else { return { hasChanges, - nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, isTimeAware), + nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, this.isTimeAware()), }; } } @@ -403,33 +401,28 @@ export class VectorStyle implements IVectorStyle { */ async getDescriptorWithUpdatedStyleProps( currentFields: IField[], - mapColors: string[], - previousFields: IField[] + previousFields: IField[], + mapColors: string[] ) { const styleFieldsHelper = await createStyleFieldsHelper(currentFields); - const originalProperties = this.getRawProperties(); - - if (previousFields.length === currentFields.length) { - return await VectorStyle.updateFieldsInDescriptor( - currentFields, - styleFieldsHelper, - originalProperties, - previousFields, - mapColors, - this.isTimeAware(), - this.getAllStyleProperties().filter((f) => f.isDynamic()) - ); - } else { - // Metrics got added and/or deleted - return await VectorStyle.deleteFieldsFromDescriptorAndUpdateStyling( - currentFields, - styleFieldsHelper, - originalProperties, - mapColors, - false, - this.isTimeAware() - ); - } + + return previousFields.length === currentFields.length + ? // Field-config changed + await this._updateFieldsInDescriptor( + currentFields, + styleFieldsHelper, + this.getRawProperties(), + previousFields, + mapColors + ) + : // Deletions or additions + await this._deleteFieldsFromDescriptorAndUpdateStyling( + currentFields, + styleFieldsHelper, + this.getRawProperties(), + mapColors, + false + ); } getType() { @@ -989,7 +982,7 @@ export class VectorStyle implements IVectorStyle { } function getDynamicOptions( - originalProperties, + originalProperties: VectorStylePropertiesDescriptor, key: VECTOR_STYLES ): DynamicStylePropertyOptions | null { if (!originalProperties[key]) { From 54eacb3c503d3deef2e69b35cf07053ba4ef0671 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 16:44:00 -0500 Subject: [PATCH 29/62] add test covergage --- .../properties/dynamic_style_property.tsx | 1 - .../styles/vector/style_fields_helper.test.ts | 122 ++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index 6da48b05a3479..d25def3c8f1c9 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -251,7 +251,6 @@ export class DynamicStyleProperty currentField: IESAggField, previousFieldDescriptor: StylePropertyField ): Promise { - // Todo: individual style property classes would need to override this with "smart" behavior if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { // Don't support auto-switching for top-term-percentages return; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts new file mode 100644 index 0000000000000..881e3e35c3b37 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts @@ -0,0 +1,122 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../common/constants'; +import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper'; +import { AbstractField } from '../../fields/field'; + +class MockField extends AbstractField { + private readonly _dataType: string; + private readonly _supportsAutoDomain: boolean; + constructor({ dataType, supportsAutoDomain }: { dataType: string; supportsAutoDomain: boolean }) { + super({ fieldName: 'foobar_' + dataType, origin: FIELD_ORIGIN.SOURCE }); + this._dataType = dataType; + this._supportsAutoDomain = supportsAutoDomain; + } + async getDataType() { + return this._dataType; + } + + supportsAutoDomain(): boolean { + return this._supportsAutoDomain; + } +} + +describe('StyleFieldHelper', () => { + describe('isFieldDataTypeCompatibleWithStyleType', () => { + async function createHelper(supportsAutoDomain: boolean): StyleFieldsHelper { + const stringField = new MockField({ + dataType: 'string', + supportsAutoDomain, + }); + const numberField = new MockField({ + dataType: 'number', + supportsAutoDomain, + }); + const dateField = new MockField({ + dataType: 'date', + supportsAutoDomain, + }); + return { + styleFieldHelper: await createStyleFieldsHelper([stringField, numberField, dateField]), + stringField, + numberField, + dateField, + }; + } + + test('Should validate colors for all data types', async () => { + const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); + + [ + VECTOR_STYLES.FILL_COLOR, + VECTOR_STYLES.LINE_COLOR, + VECTOR_STYLES.LABEL_COLOR, + VECTOR_STYLES.LABEL_BORDER_COLOR, + ].forEach((styleType) => { + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) + ).toEqual(true); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) + ).toEqual(true); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) + ).toEqual(true); + }); + }); + + test('Should validate sizes for all number types', async () => { + const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); + + [VECTOR_STYLES.LINE_WIDTH, VECTOR_STYLES.LABEL_SIZE, VECTOR_STYLES.ICON_SIZE].forEach( + (styleType) => { + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) + ).toEqual(true); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) + ).toEqual(true); + } + ); + }); + + test('Should validate orientation only number types', async () => { + const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); + + [VECTOR_STYLES.ICON_ORIENTATION].forEach((styleType) => { + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) + ).toEqual(true); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) + ).toEqual(false); + }); + }); + + test('Should not validate label_border_size', async () => { + const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); + + [VECTOR_STYLES.LABEL_BORDER_SIZE].forEach((styleType) => { + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) + ).toEqual(false); + }); + }); + }); +}); From 001e0e148aa1ca897516f006914195f2d115c842 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 16:48:50 -0500 Subject: [PATCH 30/62] add edge case test --- .../styles/vector/style_fields_helper.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts index 881e3e35c3b37..89345053f1606 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts @@ -87,6 +87,24 @@ describe('StyleFieldHelper', () => { ); }); + test('Should not validate sizes if autodomain is not enabled', async () => { + const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(false); + + [VECTOR_STYLES.LINE_WIDTH, VECTOR_STYLES.LABEL_SIZE, VECTOR_STYLES.ICON_SIZE].forEach( + (styleType) => { + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) + ).toEqual(false); + expect( + styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) + ).toEqual(false); + } + ); + }); + test('Should validate orientation only number types', async () => { const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); From 6b70fcb69dcf32e852f33a584abf5704e61494fd Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 17:21:58 -0500 Subject: [PATCH 31/62] fix test for new behavior --- .../styles/vector/vector_style.test.js | 164 +++++++++++------- .../classes/styles/vector/vector_style.tsx | 24 +-- 2 files changed, 111 insertions(+), 77 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js index d6b4de0ce31df..94090c8abfe4f 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.test.js @@ -31,8 +31,8 @@ class MockSource { } } -describe('getDescriptorWithMissingStylePropsRemoved', () => { - const fieldName = 'doIStillExist'; +describe('getDescriptorWithUpdatedStyleProps', () => { + const previousFieldName = 'doIStillExist'; const mapColors = []; const properties = { fillColor: { @@ -43,7 +43,7 @@ describe('getDescriptorWithMissingStylePropsRemoved', () => { type: STYLE_TYPE.DYNAMIC, options: { field: { - name: fieldName, + name: previousFieldName, origin: FIELD_ORIGIN.SOURCE, }, }, @@ -53,89 +53,123 @@ describe('getDescriptorWithMissingStylePropsRemoved', () => { options: { minSize: 1, maxSize: 10, - field: { name: fieldName, origin: FIELD_ORIGIN.SOURCE }, + field: { name: previousFieldName, origin: FIELD_ORIGIN.SOURCE }, }, }, }; + const previousFields = [new MockField({ fieldName: previousFieldName })]; + beforeEach(() => { require('../../../kibana_services').getUiSettings = () => ({ get: jest.fn(), }); }); - it('Should return no changes when next ordinal fields contain existing style property fields', async () => { - const vectorStyle = new VectorStyle({ properties }, new MockSource()); + describe('When there is no mismatch in configuration', () => { + it('Should return no changes when next ordinal fields contain existing style property fields', async () => { + const vectorStyle = new VectorStyle({ properties }, new MockSource()); - const nextFields = [new MockField({ fieldName, dataType: 'number' })]; - const { hasChanges } = await vectorStyle.getDescriptorWithUpdatedStyleProps( - nextFields, - mapColors - ); - expect(hasChanges).toBe(false); + const nextFields = [new MockField({ fieldName: previousFieldName, dataType: 'number' })]; + const { hasChanges } = await vectorStyle.getDescriptorWithUpdatedStyleProps( + nextFields, + previousFields, + mapColors + ); + expect(hasChanges).toBe(false); + }); }); - it('Should clear missing fields when next ordinal fields do not contain existing style property fields', async () => { - const vectorStyle = new VectorStyle({ properties }, new MockSource()); + describe('When styles should revert to static styling', () => { + it('Should convert dynamic styles to static styles when there are no next fields', async () => { + const vectorStyle = new VectorStyle({ properties }, new MockSource()); - const nextFields = [new MockField({ fieldName: 'someOtherField', dataType: 'number' })]; - const { - hasChanges, - nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); - expect(hasChanges).toBe(true); - expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ - options: {}, - type: 'DYNAMIC', - }); - expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ - options: { - minSize: 1, - maxSize: 10, - }, - type: 'DYNAMIC', + const nextFields = []; + const { + hasChanges, + nextStyleDescriptor, + } = await vectorStyle.getDescriptorWithUpdatedStyleProps( + nextFields, + previousFields, + mapColors + ); + expect(hasChanges).toBe(true); + expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ + options: { + color: '#41937c', + }, + type: 'STATIC', + }); + expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ + options: { + size: 6, + }, + type: 'STATIC', + }); }); - }); - it('Should convert dynamic styles to static styles when there are no next fields', async () => { - const vectorStyle = new VectorStyle({ properties }, new MockSource()); + it('Should convert dynamic ICON_SIZE static style when there are no next ordinal fields', async () => { + const vectorStyle = new VectorStyle({ properties }, new MockSource()); - const nextFields = []; - const { - hasChanges, - nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); - expect(hasChanges).toBe(true); - expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ - options: { - color: '#41937c', - }, - type: 'STATIC', - }); - expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ - options: { - size: 6, - }, - type: 'STATIC', + const nextFields = [ + new MockField({ + fieldName: previousFieldName, + dataType: 'number', + supportsAutoDomain: false, + }), + ]; + const { + hasChanges, + nextStyleDescriptor, + } = await vectorStyle.getDescriptorWithUpdatedStyleProps( + nextFields, + previousFields, + mapColors + ); + expect(hasChanges).toBe(true); + expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ + options: { + size: 6, + }, + type: 'STATIC', + }); }); }); - it('Should convert dynamic ICON_SIZE static style when there are no next ordinal fields', async () => { - const vectorStyle = new VectorStyle({ properties }, new MockSource()); + describe('When styles should not be cleared', () => { + it('Should update field in styles when the fields and style combination remains compatible', async () => { + const vectorStyle = new VectorStyle({ properties }, new MockSource()); - const nextFields = [ - new MockField({ fieldName, dataType: 'number', supportsAutoDomain: false }), - ]; - const { - hasChanges, - nextStyleDescriptor, - } = await vectorStyle.getDescriptorWithUpdatedStyleProps(nextFields, mapColors); - expect(hasChanges).toBe(true); - expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ - options: { - size: 6, - }, - type: 'STATIC', + const nextFields = [new MockField({ fieldName: 'someOtherField', dataType: 'number' })]; + const { + hasChanges, + nextStyleDescriptor, + } = await vectorStyle.getDescriptorWithUpdatedStyleProps( + nextFields, + previousFields, + mapColors + ); + expect(hasChanges).toBe(true); + expect(nextStyleDescriptor.properties[VECTOR_STYLES.LINE_COLOR]).toEqual({ + options: { + field: { + name: 'someOtherField', + origin: FIELD_ORIGIN.SOURCE, + }, + }, + type: 'DYNAMIC', + }); + expect(nextStyleDescriptor.properties[VECTOR_STYLES.ICON_SIZE]).toEqual({ + options: { + minSize: 1, + maxSize: 10, + field: { + name: 'someOtherField', + origin: FIELD_ORIGIN.SOURCE, + }, + }, + type: 'DYNAMIC', + }); }); }); }); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 64ad4db5adeb5..e8ebfadbf1b69 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -173,7 +173,7 @@ export class VectorStyle implements IVectorStyle { } async _updateFieldsInDescriptor( - currentFields: IField[], + nextFields: IField[], styleFieldsHelper: StyleFieldsHelper, originalProperties: VectorStylePropertiesDescriptor, previousFields: IField[], @@ -186,7 +186,7 @@ export class VectorStyle implements IVectorStyle { return; } - const matchingField = currentFields.find((field) => { + const matchingField = nextFields.find((field) => { return ( dynamicOptions && dynamicOptions.field && dynamicOptions.field.name === field.getName() ); @@ -198,8 +198,8 @@ export class VectorStyle implements IVectorStyle { let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; - const currentField = currentFields[i]; - if (previousField.isEqual(currentField)) { + const nextField = nextFields[i]; + if (previousField.isEqual(nextField)) { continue; } @@ -215,12 +215,12 @@ export class VectorStyle implements IVectorStyle { let newFieldDescriptor: StylePropertyField | undefined; const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( - currentField, + nextField, dynamicProperty.getStyleName() ); if (isFieldDataTypeCompatible) { newFieldDescriptor = await dynamicProperty.rectifyFieldDescriptor( - currentField as IESAggField, + nextField as IESAggField, { origin: previousField.getOrigin(), name: previousField.getName(), @@ -241,7 +241,7 @@ export class VectorStyle implements IVectorStyle { // Revert left-over invalid props to static styling, if necessary return this._deleteFieldsFromDescriptorAndUpdateStyling( - currentFields, + nextFields, styleFieldsHelper, originalProperties, mapColors, @@ -400,16 +400,16 @@ export class VectorStyle implements IVectorStyle { * can then use to update store state via dispatch. */ async getDescriptorWithUpdatedStyleProps( - currentFields: IField[], + nextFields: IField[], previousFields: IField[], mapColors: string[] ) { - const styleFieldsHelper = await createStyleFieldsHelper(currentFields); + const styleFieldsHelper = await createStyleFieldsHelper(nextFields); - return previousFields.length === currentFields.length + return previousFields.length === nextFields.length ? // Field-config changed await this._updateFieldsInDescriptor( - currentFields, + nextFields, styleFieldsHelper, this.getRawProperties(), previousFields, @@ -417,7 +417,7 @@ export class VectorStyle implements IVectorStyle { ) : // Deletions or additions await this._deleteFieldsFromDescriptorAndUpdateStyling( - currentFields, + nextFields, styleFieldsHelper, this.getRawProperties(), mapColors, From 361486a3a561894873e9c577e17ec2819338b152 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 17:26:09 -0500 Subject: [PATCH 32/62] fix rum test --- .../__tests__/__mocks__/regions_layer.mock.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts index 6d259a5a2e48c..9ae922015e943 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts @@ -12,6 +12,7 @@ export const mockLayerList = [ minZoom: 0, maxZoom: 24, alpha: 1, + areLabelsOnTop: true, visible: true, style: { type: 'TILE' }, type: 'VECTOR_TILE', From 67c1362dba3d9cd53f020b7aaef04de017c6ea32 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 17:33:15 -0500 Subject: [PATCH 33/62] type fix --- .../classes/styles/vector/style_fields_helper.test.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts index 89345053f1606..6109fea7b34aa 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts @@ -6,7 +6,7 @@ import { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../common/constants'; import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper'; -import { AbstractField } from '../../fields/field'; +import { AbstractField, IField } from '../../fields/field'; class MockField extends AbstractField { private readonly _dataType: string; @@ -27,7 +27,14 @@ class MockField extends AbstractField { describe('StyleFieldHelper', () => { describe('isFieldDataTypeCompatibleWithStyleType', () => { - async function createHelper(supportsAutoDomain: boolean): StyleFieldsHelper { + async function createHelper( + supportsAutoDomain: boolean + ): Promise<{ + styleFieldHelper: StyleFieldsHelper; + stringField: IField; + numberField: IField; + dateField: IField; + }> { const stringField = new MockField({ dataType: 'string', supportsAutoDomain, From c2b0750531c0e84375b6c0fe03f07acfc4555277 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 24 Nov 2020 18:42:56 -0500 Subject: [PATCH 34/62] type fixes --- .../maps/public/classes/fields/agg/count_agg_field.ts | 4 ++-- .../maps/public/components/metrics_editor/metric_editor.tsx | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts index a4562c91e92a6..0d0091117d299 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/count_agg_field.ts @@ -14,9 +14,9 @@ import { IESAggField, CountAggFieldParams } from './agg_field_types'; // Agg without field. Essentially a count-aggregation. export class CountAggField implements IESAggField { - private readonly _source: IESAggSource; + protected readonly _source: IESAggSource; private readonly _origin: FIELD_ORIGIN; - private readonly _label?: string; + protected readonly _label?: string; private readonly _canReadFromGeoJson: boolean; constructor({ label, source, origin, canReadFromGeoJson = true }: CountAggFieldParams) { diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index a75d6734bf2e3..40e27c76727fe 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { ChangeEvent, Fragment } from 'react'; +import React, { ChangeEvent, Fragment, MouseEvent } from 'react'; import { i18n } from '@kbn/i18n'; import { @@ -99,7 +99,8 @@ export function MetricEditor({ field: fieldName, }); }; - const onPercentileChange = (e: MouseEvent) => { + + const onPercentileChange = (e: ChangeEvent | MouseEvent) => { if (metric.type !== AGG_TYPE.PERCENTILE) { return; } From a14e3f02418f3a601bf07e78661670b2b7e6b4e7 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 25 Nov 2020 09:53:45 -0500 Subject: [PATCH 35/62] type fix --- .../maps/public/components/metrics_editor/metric_editor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 40e27c76727fe..1b9731ea0d4e0 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -106,7 +106,7 @@ export function MetricEditor({ } onChange({ ...metric, - percentile: parseInt(e.target.value, 10), + percentile: parseInt((e.target as HTMLInputElement).value, 10), }); }; const onLabelChange = (e: ChangeEvent) => { From 2069fcdbd060f0bc4adab2ddfad5ed9d7af01c08 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 25 Nov 2020 10:23:06 -0500 Subject: [PATCH 36/62] fix test --- .../layers/create_tile_map_layer_descriptor.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts index 291d25b94e651..4db2edc28f79f 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts @@ -14,6 +14,7 @@ import { import { AGG_TYPE, COLOR_MAP_TYPE, + DEFAULT_PERCENTILE, FIELD_ORIGIN, GRID_RESOLUTION, RENDER_AS, @@ -61,14 +62,16 @@ export function createAggDescriptor( if (!aggType || aggType === AGG_TYPE.COUNT || !metricFieldName) { return { type: AGG_TYPE.COUNT }; - } else if (aggType === AGG_TYPE.PERCENTILE) { - return { type: aggType, field: metricFieldName, percentile: 50 }; + } + + if (isHeatmap(mapType)) { + return isMetricCountable(aggType) + ? { type: aggType, field: metricFieldName } + : { type: AGG_TYPE.COUNT }; } else { - if (isHeatmap(mapType) && isMetricCountable(aggType)) { - return { type: AGG_TYPE.COUNT }; - } else { - return { type: aggType, field: metricFieldName }; - } + return aggType === AGG_TYPE.PERCENTILE + ? { type: aggType, field: metricFieldName, percentile: DEFAULT_PERCENTILE } + : { type: aggType, field: metricFieldName }; } } From f23c642f75c04a41544fe26f862435ebfb49ef8a Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 25 Nov 2020 10:44:52 -0500 Subject: [PATCH 37/62] simplify --- .../create_tile_map_layer_descriptor.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts index 4db2edc28f79f..6cfb7540b866c 100644 --- a/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts +++ b/x-pack/plugins/maps/public/classes/layers/create_tile_map_layer_descriptor.ts @@ -60,19 +60,18 @@ export function createAggDescriptor( }); const aggType = aggTypeKey ? AGG_TYPE[aggTypeKey as keyof typeof AGG_TYPE] : undefined; - if (!aggType || aggType === AGG_TYPE.COUNT || !metricFieldName) { + if ( + !aggType || + aggType === AGG_TYPE.COUNT || + !metricFieldName || + (isHeatmap(mapType) && !isMetricCountable(aggType)) + ) { return { type: AGG_TYPE.COUNT }; } - if (isHeatmap(mapType)) { - return isMetricCountable(aggType) - ? { type: aggType, field: metricFieldName } - : { type: AGG_TYPE.COUNT }; - } else { - return aggType === AGG_TYPE.PERCENTILE - ? { type: aggType, field: metricFieldName, percentile: DEFAULT_PERCENTILE } - : { type: aggType, field: metricFieldName }; - } + return aggType === AGG_TYPE.PERCENTILE + ? { type: aggType, field: metricFieldName, percentile: DEFAULT_PERCENTILE } + : { type: aggType, field: metricFieldName }; } export function createTileMapLayerDescriptor({ From 0efe4010fa533175e551ba80cbab0783b36830e1 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 25 Nov 2020 15:25:41 -0500 Subject: [PATCH 38/62] revert uptime change --- .../__tests__/__mocks__/regions_layer.mock.ts | 1 - .../app/RumDashboard/VisitorBreakdownMap/useLayerList.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts index 9ae922015e943..6d259a5a2e48c 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__tests__/__mocks__/regions_layer.mock.ts @@ -12,7 +12,6 @@ export const mockLayerList = [ minZoom: 0, maxZoom: 24, alpha: 1, - areLabelsOnTop: true, visible: true, style: { type: 'TILE' }, type: 'VECTOR_TILE', diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts index 0c922ec361ccd..a1cdf7bb646e5 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/useLayerList.ts @@ -100,7 +100,6 @@ export function useLayerList() { visible: true, style: { type: 'TILE' }, type: 'VECTOR_TILE', - areLabelsOnTop: true, }; ES_TERM_SOURCE_COUNTRY.whereQuery = getWhereQuery(serviceName!); From dc5c8c8c92545a7422ecf97636042e7cc2b1a8a1 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 30 Nov 2020 10:57:32 -0500 Subject: [PATCH 39/62] fix term join parsing --- .../plugins/maps/common/elasticsearch_util/es_agg_utils.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts index e0cf0fb166c8e..665aea400e991 100644 --- a/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts +++ b/x-pack/plugins/maps/common/elasticsearch_util/es_agg_utils.ts @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import _ from 'lodash'; import { IndexPattern, IFieldType } from '../../../../../src/plugins/data/common'; -import { AGG_TYPE, TOP_TERM_PERCENTAGE_SUFFIX } from '../constants'; +import { AGG_TYPE, JOIN_FIELD_NAME_PREFIX, TOP_TERM_PERCENTAGE_SUFFIX } from '../constants'; export type BucketProperties = Record; export type PropertiesMap = Map; @@ -64,7 +64,10 @@ export function extractPropertiesFromBucket( ); } } else { - if (key.startsWith(AGG_TYPE.PERCENTILE)) { + if ( + key.startsWith(AGG_TYPE.PERCENTILE) || + key.startsWith(JOIN_FIELD_NAME_PREFIX + AGG_TYPE.PERCENTILE) + ) { const values = bucket[key].values; for (const k in values) { if (values.hasOwnProperty(k)) { From 6ea286b7a286c8f8f3a6ba026cd8eaf18979cc07 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 30 Nov 2020 11:55:25 -0500 Subject: [PATCH 40/62] feedback --- .../maps/public/actions/layer_actions.ts | 41 ++++-------- .../properties/dynamic_style_property.tsx | 19 ------ .../styles/vector/style_fields_helper.test.ts | 60 +++++------------ .../styles/vector/style_fields_helper.ts | 4 +- .../classes/styles/vector/vector_style.tsx | 65 +++++++++++-------- 5 files changed, 70 insertions(+), 119 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index ba8aab9fb8e49..6dac5244c508f 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -286,33 +286,21 @@ export function updateSourceProp( dispatch: ThunkDispatch, getState: () => MapStoreState ) => { + const layer = getLayerById(layerId, getState()); + const previousFields = await (layer as IVectorLayer).getFields(); + dispatch({ + type: UPDATE_SOURCE_PROP, + layerId, + propName, + value, + }); + if (newLayerType) { + dispatch(updateLayerType(layerId, newLayerType)); + } if (propName === 'metrics') { - const layer = getLayerById(layerId, getState()); - const oldFields = await (layer as IVectorLayer).getFields(); - dispatch({ - type: UPDATE_SOURCE_PROP, - layerId, - propName, - value, - }); - if (newLayerType) { - dispatch(updateLayerType(layerId, newLayerType)); - } - await dispatch(updateStyleProperties(layerId, oldFields as IESAggField[])); - dispatch(syncDataForLayerId(layerId)); - } else { - dispatch({ - type: UPDATE_SOURCE_PROP, - layerId, - propName, - value, - }); - if (newLayerType) { - dispatch(updateLayerType(layerId, newLayerType)); - } - // await dispatch(updateStyleProperties(layerId)); - dispatch(syncDataForLayerId(layerId)); + await dispatch(updateStyleProperties(layerId, previousFields as IESAggField[])); } + dispatch(syncDataForLayerId(layerId)); }; } @@ -507,13 +495,12 @@ export function updateLayerStyleForSelectedLayer(styleDescriptor: StyleDescripto export function setJoinsForLayer(layer: ILayer, joins: JoinDescriptor[]) { return async (dispatch: ThunkDispatch) => { + const previousFields = await (layer as IVectorLayer).getFields(); await dispatch({ type: SET_JOINS, layer, joins, }); - - const previousFields = await (layer as IVectorLayer).getFields(); await dispatch(updateStyleProperties(layer.getId(), previousFields)); dispatch(syncDataForLayerId(layer.getId())); }; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index d25def3c8f1c9..96b006538986d 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -51,10 +51,6 @@ export interface IDynamicStyleProperty extends IStyleProperty { pluckOrdinalStyleMetaFromFeatures(features: Feature[]): RangeFieldMeta | null; pluckCategoricalStyleMetaFromFeatures(features: Feature[]): CategoryFieldMeta | null; getValueSuggestions(query: string): Promise; - rectifyFieldDescriptor( - currentField: IESAggField, - previousFieldDescriptor: StylePropertyField - ): Promise; enrichGeoJsonAndMbFeatureState( featureCollection: FeatureCollection, mbMap: MbMap, @@ -247,21 +243,6 @@ export class DynamicStyleProperty } as RangeFieldMeta); } - async rectifyFieldDescriptor( - currentField: IESAggField, - previousFieldDescriptor: StylePropertyField - ): Promise { - if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { - // Don't support auto-switching for top-term-percentages - return; - } - - return { - origin: previousFieldDescriptor.origin, - name: currentField.getName(), - }; - } - pluckCategoricalStyleMetaFromFeatures(features: Feature[]) { const size = this.getNumberOfCategories(); if (!this.isCategorical() || size <= 0) { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts index 6109fea7b34aa..9556862842e82 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.test.ts @@ -64,15 +64,9 @@ describe('StyleFieldHelper', () => { VECTOR_STYLES.LABEL_COLOR, VECTOR_STYLES.LABEL_BORDER_COLOR, ].forEach((styleType) => { - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) - ).toEqual(true); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) - ).toEqual(true); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) - ).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(true); }); }); @@ -81,15 +75,9 @@ describe('StyleFieldHelper', () => { [VECTOR_STYLES.LINE_WIDTH, VECTOR_STYLES.LABEL_SIZE, VECTOR_STYLES.ICON_SIZE].forEach( (styleType) => { - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) - ).toEqual(true); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) - ).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(true); } ); }); @@ -99,15 +87,9 @@ describe('StyleFieldHelper', () => { [VECTOR_STYLES.LINE_WIDTH, VECTOR_STYLES.LABEL_SIZE, VECTOR_STYLES.ICON_SIZE].forEach( (styleType) => { - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) - ).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(false); } ); }); @@ -116,15 +98,9 @@ describe('StyleFieldHelper', () => { const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); [VECTOR_STYLES.ICON_ORIENTATION].forEach((styleType) => { - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) - ).toEqual(true); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) - ).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true); + expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(false); }); }); @@ -132,15 +108,9 @@ describe('StyleFieldHelper', () => { const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true); [VECTOR_STYLES.LABEL_BORDER_SIZE].forEach((styleType) => { - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(stringField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(numberField, styleType) - ).toEqual(false); - expect( - styleFieldHelper.isFieldDataTypeCompatibleWithStyleType(dateField, styleType) - ).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(false); + expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(false); }); }); }); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts index c727e4a5d81f3..d36cf575a9bd8 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts +++ b/x-pack/plugins/maps/public/classes/styles/vector/style_fields_helper.ts @@ -69,9 +69,9 @@ export class StyleFieldsHelper { this._ordinalFields = ordinalFields; } - isFieldDataTypeCompatibleWithStyleType(field: IField, styleName: VECTOR_STYLES): boolean { + hasFieldForStyle(field: IField, styleName: VECTOR_STYLES): boolean { const fieldList = this.getFieldsForStyle(styleName); - return !!fieldList.find((styleField) => field.getName() === styleField.name); + return fieldList.some((styleField) => field.getName() === styleField.name); } getFieldsForStyle(styleName: VECTOR_STYLES): StyleField[] { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index e8ebfadbf1b69..0e2565f366b45 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -17,6 +17,7 @@ import { LAYER_STYLE_TYPE, SOURCE_FORMATTERS_DATA_REQUEST_ID, STYLE_TYPE, + TOP_TERM_PERCENTAGE_SUFFIX, VECTOR_SHAPE_TYPE, VECTOR_STYLES, } from '../../../../common/constants'; @@ -83,7 +84,7 @@ export interface IVectorStyle extends IStyle { getStyleMeta(): StyleMeta; getDescriptorWithUpdatedStyleProps( nextFields: IField[], - oldFields: IField[], + previousFields: IField[], mapColors: string[] ): Promise<{ hasChanges: boolean; nextStyleDescriptor?: VectorStyleDescriptor }>; pluckStyleMetaFromSourceDataRequest(sourceDataRequest: DataRequest): Promise; @@ -179,21 +180,21 @@ export class VectorStyle implements IVectorStyle { previousFields: IField[], mapColors: string[] ) { - const invalidDynamicProperties = (Object.keys(originalProperties) as VECTOR_STYLES[]).filter( - (key) => { - const dynamicOptions = getDynamicOptions(originalProperties, key); - if (!dynamicOptions || !dynamicOptions.field || !dynamicOptions.field.name) { - return; - } - - const matchingField = nextFields.find((field) => { - return ( - dynamicOptions && dynamicOptions.field && dynamicOptions.field.name === field.getName() - ); - }); - return !matchingField; + const invalidStyleNames: VECTOR_STYLES[] = (Object.keys( + originalProperties + ) as VECTOR_STYLES[]).filter((key) => { + const dynamicOptions = getDynamicOptions(originalProperties, key); + if (!dynamicOptions || !dynamicOptions.field || !dynamicOptions.field.name) { + return; } - ); + + const hasMatchingField = nextFields.some((field) => { + return ( + dynamicOptions && dynamicOptions.field && dynamicOptions.field.name === field.getName() + ); + }); + return !hasMatchingField; + }); let hasChanges = false; for (let i = 0; i < previousFields.length; i++) { @@ -204,9 +205,9 @@ export class VectorStyle implements IVectorStyle { } // Check if the updated field can be assigned to any of the broken style-properties. - for (let j = 0; j < invalidDynamicProperties.length; j++) { + for (let j = 0; j < invalidStyleNames.length; j++) { const dynamicProperty: IDynamicStyleProperty = this.getAllStyleProperties().find( - (d) => d.getStyleName() === invalidDynamicProperties[j] + (d) => d.getStyleName() === invalidStyleNames[j] ) as IDynamicStyleProperty; if (!dynamicProperty) { @@ -214,22 +215,19 @@ export class VectorStyle implements IVectorStyle { } let newFieldDescriptor: StylePropertyField | undefined; - const isFieldDataTypeCompatible = styleFieldsHelper.isFieldDataTypeCompatibleWithStyleType( + const isFieldDataTypeCompatible = styleFieldsHelper.hasFieldForStyle( nextField, dynamicProperty.getStyleName() ); if (isFieldDataTypeCompatible) { - newFieldDescriptor = await dynamicProperty.rectifyFieldDescriptor( - nextField as IESAggField, - { - origin: previousField.getOrigin(), - name: previousField.getName(), - } - ); + newFieldDescriptor = await rectifyFieldDescriptor(nextField as IESAggField, { + origin: previousField.getOrigin(), + name: previousField.getName(), + }); if (newFieldDescriptor) { hasChanges = true; - invalidDynamicProperties.splice(j, 1); + invalidStyleNames.splice(j, 1); j--; } } @@ -999,3 +997,18 @@ function getDynamicOptions( } return propertyDescriptor.options as DynamicStylePropertyOptions; } + +function rectifyFieldDescriptor( + currentField: IESAggField, + previousFieldDescriptor: StylePropertyField +): Promise { + if (previousFieldDescriptor.name.endsWith(TOP_TERM_PERCENTAGE_SUFFIX)) { + // Don't support auto-switching for top-term-percentages + return; + } + + return { + origin: previousFieldDescriptor.origin, + name: currentField.getName(), + }; +} From 5d6fa3e4f03f41be6ca8fb55bb7c4a3396821fee Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 30 Nov 2020 15:16:05 -0500 Subject: [PATCH 41/62] rearrange --- .../maps/public/actions/layer_actions.ts | 34 +++- .../classes/styles/vector/vector_style.tsx | 157 +++++++++--------- 2 files changed, 106 insertions(+), 85 deletions(-) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.ts b/x-pack/plugins/maps/public/actions/layer_actions.ts index 6dac5244c508f..6a7a9d98f7765 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.ts @@ -276,18 +276,37 @@ export function updateLayerOrder(newLayerOrder: number[]) { }; } -export function updateSourceProp( - layerId: string, - propName: string, - value: unknown, - newLayerType?: LAYER_TYPE -) { +export function updateMetricsProp(layerId, value) { return async ( dispatch: ThunkDispatch, getState: () => MapStoreState ) => { const layer = getLayerById(layerId, getState()); + await dispatch({ + type: UPDATE_SOURCE_PROP, + layerId, + propName: 'metrics', + value, + }); const previousFields = await (layer as IVectorLayer).getFields(); + await dispatch(updateStyleProperties(layerId, previousFields as IESAggField[])); + dispatch(syncDataForLayerId(layerId)); + }; +} + +export function updateSourceProp( + layerId: string, + propName: string, + value: unknown, + newLayerType?: LAYER_TYPE +) { + return async (dispatch: ThunkDispatch) => { + if (propName === 'metrics') { + if (newLayerType) { + throw new Error('May not change layer-type when modifying metrics source-property'); + } + return await dispatch(updateMetricsProp(layerId, value)); + } dispatch({ type: UPDATE_SOURCE_PROP, layerId, @@ -297,9 +316,6 @@ export function updateSourceProp( if (newLayerType) { dispatch(updateLayerType(layerId, newLayerType)); } - if (propName === 'metrics') { - await dispatch(updateStyleProperties(layerId, previousFields as IESAggField[])); - } dispatch(syncDataForLayerId(layerId)); }; } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 0e2565f366b45..73f2086813b83 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -173,6 +173,74 @@ export class VectorStyle implements IVectorStyle { return getDefaultStaticProperties(mapColors); } + constructor( + descriptor: VectorStyleDescriptor | null, + source: IVectorSource, + layer: IVectorLayer + ) { + this._source = source; + this._layer = layer; + this._descriptor = descriptor + ? { + ...descriptor, + ...VectorStyle.createDescriptor(descriptor.properties, descriptor.isTimeAware), + } + : VectorStyle.createDescriptor(); + + this._styleMeta = new StyleMeta(this._descriptor.__styleMeta); + + this._symbolizeAsStyleProperty = new SymbolizeAsProperty( + this._descriptor.properties[VECTOR_STYLES.SYMBOLIZE_AS].options, + VECTOR_STYLES.SYMBOLIZE_AS + ); + this._lineColorStyleProperty = this._makeColorProperty( + this._descriptor.properties[VECTOR_STYLES.LINE_COLOR], + VECTOR_STYLES.LINE_COLOR + ); + this._fillColorStyleProperty = this._makeColorProperty( + this._descriptor.properties[VECTOR_STYLES.FILL_COLOR], + VECTOR_STYLES.FILL_COLOR + ); + this._lineWidthStyleProperty = this._makeSizeProperty( + this._descriptor.properties[VECTOR_STYLES.LINE_WIDTH], + VECTOR_STYLES.LINE_WIDTH, + this._symbolizeAsStyleProperty.isSymbolizedAsIcon() + ); + this._iconStyleProperty = this._makeIconProperty( + this._descriptor.properties[VECTOR_STYLES.ICON] + ); + this._iconSizeStyleProperty = this._makeSizeProperty( + this._descriptor.properties[VECTOR_STYLES.ICON_SIZE], + VECTOR_STYLES.ICON_SIZE, + this._symbolizeAsStyleProperty.isSymbolizedAsIcon() + ); + this._iconOrientationProperty = this._makeOrientationProperty( + this._descriptor.properties[VECTOR_STYLES.ICON_ORIENTATION], + VECTOR_STYLES.ICON_ORIENTATION + ); + this._labelStyleProperty = this._makeLabelProperty( + this._descriptor.properties[VECTOR_STYLES.LABEL_TEXT] + ); + this._labelSizeStyleProperty = this._makeSizeProperty( + this._descriptor.properties[VECTOR_STYLES.LABEL_SIZE], + VECTOR_STYLES.LABEL_SIZE, + this._symbolizeAsStyleProperty.isSymbolizedAsIcon() + ); + this._labelColorStyleProperty = this._makeColorProperty( + this._descriptor.properties[VECTOR_STYLES.LABEL_COLOR], + VECTOR_STYLES.LABEL_COLOR + ); + this._labelBorderColorStyleProperty = this._makeColorProperty( + this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR], + VECTOR_STYLES.LABEL_BORDER_COLOR + ); + this._labelBorderSizeStyleProperty = new LabelBorderSizeProperty( + this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_SIZE].options, + VECTOR_STYLES.LABEL_BORDER_SIZE, + this._labelSizeStyleProperty + ); + } + async _updateFieldsInDescriptor( nextFields: IField[], styleFieldsHelper: StyleFieldsHelper, @@ -237,14 +305,19 @@ export class VectorStyle implements IVectorStyle { } } - // Revert left-over invalid props to static styling, if necessary - return this._deleteFieldsFromDescriptorAndUpdateStyling( - nextFields, - styleFieldsHelper, - originalProperties, - mapColors, - hasChanges - ); + return { + hasChanges, + nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, this.isTimeAware()), + }; + + // // Revert left-over invalid props to static styling, if necessary + // return this._deleteFieldsFromDescriptorAndUpdateStyling( + // nextFields, + // styleFieldsHelper, + // originalProperties, + // mapColors, + // hasChanges + // ); } async _deleteFieldsFromDescriptorAndUpdateStyling( @@ -318,74 +391,6 @@ export class VectorStyle implements IVectorStyle { } } - constructor( - descriptor: VectorStyleDescriptor | null, - source: IVectorSource, - layer: IVectorLayer - ) { - this._source = source; - this._layer = layer; - this._descriptor = descriptor - ? { - ...descriptor, - ...VectorStyle.createDescriptor(descriptor.properties, descriptor.isTimeAware), - } - : VectorStyle.createDescriptor(); - - this._styleMeta = new StyleMeta(this._descriptor.__styleMeta); - - this._symbolizeAsStyleProperty = new SymbolizeAsProperty( - this._descriptor.properties[VECTOR_STYLES.SYMBOLIZE_AS].options, - VECTOR_STYLES.SYMBOLIZE_AS - ); - this._lineColorStyleProperty = this._makeColorProperty( - this._descriptor.properties[VECTOR_STYLES.LINE_COLOR], - VECTOR_STYLES.LINE_COLOR - ); - this._fillColorStyleProperty = this._makeColorProperty( - this._descriptor.properties[VECTOR_STYLES.FILL_COLOR], - VECTOR_STYLES.FILL_COLOR - ); - this._lineWidthStyleProperty = this._makeSizeProperty( - this._descriptor.properties[VECTOR_STYLES.LINE_WIDTH], - VECTOR_STYLES.LINE_WIDTH, - this._symbolizeAsStyleProperty.isSymbolizedAsIcon() - ); - this._iconStyleProperty = this._makeIconProperty( - this._descriptor.properties[VECTOR_STYLES.ICON] - ); - this._iconSizeStyleProperty = this._makeSizeProperty( - this._descriptor.properties[VECTOR_STYLES.ICON_SIZE], - VECTOR_STYLES.ICON_SIZE, - this._symbolizeAsStyleProperty.isSymbolizedAsIcon() - ); - this._iconOrientationProperty = this._makeOrientationProperty( - this._descriptor.properties[VECTOR_STYLES.ICON_ORIENTATION], - VECTOR_STYLES.ICON_ORIENTATION - ); - this._labelStyleProperty = this._makeLabelProperty( - this._descriptor.properties[VECTOR_STYLES.LABEL_TEXT] - ); - this._labelSizeStyleProperty = this._makeSizeProperty( - this._descriptor.properties[VECTOR_STYLES.LABEL_SIZE], - VECTOR_STYLES.LABEL_SIZE, - this._symbolizeAsStyleProperty.isSymbolizedAsIcon() - ); - this._labelColorStyleProperty = this._makeColorProperty( - this._descriptor.properties[VECTOR_STYLES.LABEL_COLOR], - VECTOR_STYLES.LABEL_COLOR - ); - this._labelBorderColorStyleProperty = this._makeColorProperty( - this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR], - VECTOR_STYLES.LABEL_BORDER_COLOR - ); - this._labelBorderSizeStyleProperty = new LabelBorderSizeProperty( - this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_SIZE].options, - VECTOR_STYLES.LABEL_BORDER_SIZE, - this._labelSizeStyleProperty - ); - } - /* * Changes to source descriptor and join descriptor will impact style properties. * For instance, a style property may be dynamically tied to the value of an ordinal field defined From ac2f94302e59686cdcc75cc6ab5e347fdcf76e12 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 30 Nov 2020 15:19:31 -0500 Subject: [PATCH 42/62] switch inner-outer loop --- .../classes/styles/vector/vector_style.tsx | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 73f2086813b83..a4dcad9e90e89 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -265,15 +265,16 @@ export class VectorStyle implements IVectorStyle { }); let hasChanges = false; - for (let i = 0; i < previousFields.length; i++) { - const previousField = previousFields[i]; - const nextField = nextFields[i]; - if (previousField.isEqual(nextField)) { - continue; - } - // Check if the updated field can be assigned to any of the broken style-properties. - for (let j = 0; j < invalidStyleNames.length; j++) { + for (let j = 0; j < invalidStyleNames.length; j++) { + for (let i = 0; i < previousFields.length; i++) { + const previousField = previousFields[i]; + const nextField = nextFields[i]; + if (previousField.isEqual(nextField)) { + continue; + } + + // Check if the updated field can be assigned to any of the broken style-properties. const dynamicProperty: IDynamicStyleProperty = this.getAllStyleProperties().find( (d) => d.getStyleName() === invalidStyleNames[j] ) as IDynamicStyleProperty; @@ -295,8 +296,8 @@ export class VectorStyle implements IVectorStyle { if (newFieldDescriptor) { hasChanges = true; - invalidStyleNames.splice(j, 1); - j--; + // invalidStyleNames.splice(j, 1); + // j--; } } From bb65b1dc0c3eb9bb8cb969228e376af9cef0abc8 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 30 Nov 2020 15:47:35 -0500 Subject: [PATCH 43/62] use foreach --- .../classes/styles/vector/vector_style.tsx | 31 +++---------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index a4dcad9e90e89..9251a45b71902 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -266,59 +266,38 @@ export class VectorStyle implements IVectorStyle { let hasChanges = false; - for (let j = 0; j < invalidStyleNames.length; j++) { + invalidStyleNames.forEach((invalidStyleName) => { for (let i = 0; i < previousFields.length; i++) { const previousField = previousFields[i]; const nextField = nextFields[i]; if (previousField.isEqual(nextField)) { continue; } - - // Check if the updated field can be assigned to any of the broken style-properties. - const dynamicProperty: IDynamicStyleProperty = this.getAllStyleProperties().find( - (d) => d.getStyleName() === invalidStyleNames[j] - ) as IDynamicStyleProperty; - - if (!dynamicProperty) { - continue; - } - let newFieldDescriptor: StylePropertyField | undefined; const isFieldDataTypeCompatible = styleFieldsHelper.hasFieldForStyle( nextField, - dynamicProperty.getStyleName() + invalidStyleName ); if (isFieldDataTypeCompatible) { - newFieldDescriptor = await rectifyFieldDescriptor(nextField as IESAggField, { + newFieldDescriptor = rectifyFieldDescriptor(nextField as IESAggField, { origin: previousField.getOrigin(), name: previousField.getName(), }); if (newFieldDescriptor) { hasChanges = true; - // invalidStyleNames.splice(j, 1); - // j--; } } - (originalProperties[dynamicProperty.getStyleName()]! + (originalProperties[invalidStyleName]! .options! as DynamicStylePropertyOptions).field = newFieldDescriptor; } - } + }); return { hasChanges, nextStyleDescriptor: VectorStyle.createDescriptor(originalProperties, this.isTimeAware()), }; - - // // Revert left-over invalid props to static styling, if necessary - // return this._deleteFieldsFromDescriptorAndUpdateStyling( - // nextFields, - // styleFieldsHelper, - // originalProperties, - // mapColors, - // hasChanges - // ); } async _deleteFieldsFromDescriptorAndUpdateStyling( From 13a408aff66374b78c3520c145828ff7808e8bed Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 15:23:10 -0500 Subject: [PATCH 44/62] implement new stylemeta api --- x-pack/plugins/maps/common/constants.ts | 1 - .../classes/fields/agg/percentile_agg_field.ts | 18 ++++++++++++------ .../properties/dynamic_color_property.tsx | 1 + .../properties/dynamic_style_property.tsx | 3 --- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 7bc3a1cef44e9..c267052e6dfe5 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -173,7 +173,6 @@ export const GEOCENTROID_AGG_NAME = 'gridCentroid'; export const TOP_TERM_PERCENTAGE_SUFFIX = '__percentage'; export const DEFAULT_PERCENTILE = 50; -export const PERCENTILE_AGG_NAME = 'percentile'; export const COUNT_PROP_LABEL = i18n.translate('xpack.maps.aggs.defaultCountLabel', { defaultMessage: 'count', diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index ee81194ba2665..b994a9e5eaf55 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -5,20 +5,20 @@ */ import { IndexPattern } from 'src/plugins/data/common/index_patterns/index_patterns'; -import { IField } from '../field'; import { AGG_TYPE } from '../../../../common/constants'; import { IESAggField, CountAggFieldParams } from './agg_field_types'; import { CountAggField } from './count_agg_field'; import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; +import { ESDocField } from '../es_doc_field'; export interface PercentileAggParams extends CountAggFieldParams { - esDocField?: IField; + esDocField?: ESDocField; percentile: number; } export class PercentileAggField extends CountAggField implements IESAggField { private readonly _percentile: number; - private readonly _esDocField?: IField; + private readonly _esDocField?: ESDocField; constructor(params: PercentileAggParams) { super(params); this._esDocField = params.esDocField; @@ -64,14 +64,20 @@ export class PercentileAggField extends CountAggField implements IESAggField { return AGG_TYPE.PERCENTILE; } - async getOrdinalFieldMetaRequest(): Promise { - return this._esDocField ? await this._esDocField.getOrdinalFieldMetaRequest() : null; + async getExtendedStatsFieldMetaRequest(): Promise { + return this._esDocField ? await this._esDocField.getExtendedStatsFieldMetaRequest() : null; } - async getCategoricalFieldMetaRequest(size: number): Promise { + async getCategoricalFieldMetaRequest(size: number): Promise { return this._esDocField ? await this._esDocField.getCategoricalFieldMetaRequest(size) : null; } + async getPercentilesFieldMetaRequest(percentiles: number[]): Promise { + return this._esDocField + ? await this._esDocField.getPercentilesFieldMetaRequest(percentiles) + : null; + } + isValid(): boolean { return !!this._esDocField; } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index 289bb6be3179d..e149fcae88915 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -178,6 +178,7 @@ export class DynamicColorProperty extends DynamicStyleProperty extends IStyleProperty { getFieldMetaOptions(): FieldMetaOptions; From eeda3c48128112401b2ee950beef0e4dea2e7d79 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 16:11:54 -0500 Subject: [PATCH 45/62] type fix --- .../plugins/maps/public/classes/styles/vector/vector_style.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 497bd308bdd40..1c36961aae1b1 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -17,7 +17,6 @@ import { LAYER_STYLE_TYPE, SOURCE_FORMATTERS_DATA_REQUEST_ID, STYLE_TYPE, - TOP_TERM_PERCENTAGE_SUFFIX, VECTOR_SHAPE_TYPE, VECTOR_STYLES, } from '../../../../common/constants'; From 510d4bdbe2b894345fc53fb4dc6328772cbc1cbe Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 16:16:14 -0500 Subject: [PATCH 46/62] remove crufty space --- .../classes/styles/vector/properties/dynamic_color_property.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index e149fcae88915..289bb6be3179d 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -178,7 +178,6 @@ export class DynamicColorProperty extends DynamicStyleProperty Date: Wed, 9 Dec 2020 17:19:47 -0500 Subject: [PATCH 47/62] add more test coverage --- .../classes/fields/agg/es_agg_factory.test.ts | 22 +++++ .../fields/agg/percentile_agg_field.test.ts | 84 +++++++++++++++++++ .../fields/agg/percentile_agg_field.ts | 3 +- .../properties/dynamic_color_property.tsx | 27 +----- .../public/classes/util/ordinal_suffix.ts | 32 +++++++ 5 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts create mode 100644 x-pack/plugins/maps/public/classes/util/ordinal_suffix.ts diff --git a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts index cb0bb51e374fb..0b07ec63ba2c6 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts @@ -48,4 +48,26 @@ describe('esAggFieldsFactory', () => { ); expect(fields.length).toBe(2); }); + + describe('percentile-fields', () => { + test('Should create percentile agg fields with default', () => { + const fields = esAggFieldsFactory( + { type: AGG_TYPE.PERCENTILE, field: 'myField' }, + mockEsAggSource, + FIELD_ORIGIN.SOURCE + ); + expect(fields.length).toBe(1); + expect(fields[0].getName()).toBe('agg_key_50'); + }); + + test('Should create percentile agg fields with param', () => { + const fields = esAggFieldsFactory( + { type: AGG_TYPE.PERCENTILE, field: 'myField', percentile: 90 }, + mockEsAggSource, + FIELD_ORIGIN.SOURCE + ); + expect(fields.length).toBe(1); + expect(fields[0].getName()).toBe('agg_key_90'); + }); + }); }); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts new file mode 100644 index 0000000000000..fe4d08a251c0f --- /dev/null +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; +import { IESAggSource } from '../../sources/es_agg_source'; +import { IndexPattern } from 'src/plugins/data/public'; +import { PercentileAggField } from './percentile_agg_field'; +import { ESDocField } from '../es_doc_field'; + +const mockFields = [ + { + name: 'foo*', + }, +]; +// @ts-expect-error +mockFields.getByName = (name: string) => { + return { + name, + }; +}; + +const mockIndexPattern = { + title: 'wildIndex', + fields: mockFields, +}; + +const mockEsAggSource = { + getAggKey: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_key'; + }, + getAggLabel: (aggType: AGG_TYPE, fieldName: string) => { + return 'agg_label'; + }, + getIndexPattern: async () => { + return mockIndexPattern; + }, +} as IESAggSource; + +const mockEsDocField = { + getName() { + return 'foobar'; + }, +}; + +const defaultParams = { + source: mockEsAggSource, + origin: FIELD_ORIGIN.SOURCE, +}; + +describe('percentile agg field', () => { + test('should include percentile in name', () => { + const field = new PercentileAggField({ + ...defaultParams, + esDocField: mockEsDocField as ESDocField, + percentile: 80, + }); + expect(field.getName()).toEqual('agg_key_80'); + }); + + test('should create percentile dsl', () => { + const field = new PercentileAggField({ + ...defaultParams, + esDocField: mockEsDocField as ESDocField, + percentile: 80, + }); + + expect(field.getValueAggDsl(mockIndexPattern as IndexPattern)).toEqual({ + percentiles: { field: 'foobar', percents: [80] }, + }); + }); + + test('label', async () => { + const field = new PercentileAggField({ + ...defaultParams, + esDocField: mockEsDocField as ESDocField, + percentile: 80, + }); + + expect(await field.getLabel()).toEqual('80th agg_label'); + }); +}); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index b994a9e5eaf55..977e4c4f21d71 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -10,6 +10,7 @@ import { IESAggField, CountAggFieldParams } from './agg_field_types'; import { CountAggField } from './count_agg_field'; import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; import { ESDocField } from '../es_doc_field'; +import { getOrdinalSuffix } from '../../util/ordinal_suffix'; export interface PercentileAggParams extends CountAggFieldParams { esDocField?: ESDocField; @@ -34,7 +35,7 @@ export class PercentileAggField extends CountAggField implements IESAggField { } async getLabel(): Promise { - const suffix = this._percentile === 1 ? 'st' : this._percentile === 2 ? 'nd' : 'th'; + const suffix = getOrdinalSuffix(this._percentile); return this._label ? this._label : `${this._percentile}${suffix} ${this._source.getAggLabel( diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index 289bb6be3179d..cc76a1d258563 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -5,7 +5,6 @@ */ import { Map as MbMap } from 'mapbox-gl'; -import { i18n } from '@kbn/i18n'; import React from 'react'; import { EuiTextColor } from '@elastic/eui'; import { DynamicStyleProperty } from './dynamic_style_property'; @@ -25,35 +24,11 @@ import { import { Break, BreakedLegend } from '../components/legend/breaked_legend'; import { ColorDynamicOptions, OrdinalColorStop } from '../../../../../common/descriptor_types'; import { LegendProps } from './style_property'; +import { getOrdinalSuffix } from '../../../util/ordinal_suffix'; const EMPTY_STOPS = { stops: [], defaultColor: null }; const RGBA_0000 = 'rgba(0,0,0,0)'; -function getOrdinalSuffix(value: number) { - const lastDigit = value % 10; - if (lastDigit === 1 && value !== 11) { - return i18n.translate('xpack.maps.styles.firstOrdinalSuffix', { - defaultMessage: 'st', - }); - } - - if (lastDigit === 2 && value !== 12) { - return i18n.translate('xpack.maps.styles.secondOrdinalSuffix', { - defaultMessage: 'nd', - }); - } - - if (lastDigit === 3 && value !== 13) { - return i18n.translate('xpack.maps.styles.thirdOrdinalSuffix', { - defaultMessage: 'rd', - }); - } - - return i18n.translate('xpack.maps.styles.ordinalSuffix', { - defaultMessage: 'th', - }); -} - export class DynamicColorProperty extends DynamicStyleProperty { syncCircleColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) { const color = this._getMbColor(); diff --git a/x-pack/plugins/maps/public/classes/util/ordinal_suffix.ts b/x-pack/plugins/maps/public/classes/util/ordinal_suffix.ts new file mode 100644 index 0000000000000..441f78561cbbb --- /dev/null +++ b/x-pack/plugins/maps/public/classes/util/ordinal_suffix.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export function getOrdinalSuffix(value: number) { + const lastDigit = value % 10; + if (lastDigit === 1 && value !== 11) { + return i18n.translate('xpack.maps.styles.firstOrdinalSuffix', { + defaultMessage: 'st', + }); + } + + if (lastDigit === 2 && value !== 12) { + return i18n.translate('xpack.maps.styles.secondOrdinalSuffix', { + defaultMessage: 'nd', + }); + } + + if (lastDigit === 3 && value !== 13) { + return i18n.translate('xpack.maps.styles.thirdOrdinalSuffix', { + defaultMessage: 'rd', + }); + } + + return i18n.translate('xpack.maps.styles.ordinalSuffix', { + defaultMessage: 'th', + }); +} From a66037b3e0096f5054cd3f9e0f46b623223bff61 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 18:13:00 -0500 Subject: [PATCH 48/62] remove agg field --- .../maps/public/classes/fields/agg/percentile_agg_field.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index 977e4c4f21d71..6b9b70353265e 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -12,7 +12,7 @@ import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; import { ESDocField } from '../es_doc_field'; import { getOrdinalSuffix } from '../../util/ordinal_suffix'; -export interface PercentileAggParams extends CountAggFieldParams { +interface PercentileAggParams extends CountAggFieldParams { esDocField?: ESDocField; percentile: number; } From f754916d64d6c25650b27dfb006ffd634afb71c1 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 18:21:16 -0500 Subject: [PATCH 49/62] subclass from aggfield instead --- .../fields/agg/percentile_agg_field.ts | 39 ++++--------------- 1 file changed, 8 insertions(+), 31 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index 6b9b70353265e..03991670e1121 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -7,22 +7,25 @@ import { IndexPattern } from 'src/plugins/data/common/index_patterns/index_patterns'; import { AGG_TYPE } from '../../../../common/constants'; import { IESAggField, CountAggFieldParams } from './agg_field_types'; -import { CountAggField } from './count_agg_field'; import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; import { ESDocField } from '../es_doc_field'; import { getOrdinalSuffix } from '../../util/ordinal_suffix'; +import { AggField } from './agg_field'; interface PercentileAggParams extends CountAggFieldParams { esDocField?: ESDocField; percentile: number; } -export class PercentileAggField extends CountAggField implements IESAggField { +export class PercentileAggField extends AggField implements IESAggField { private readonly _percentile: number; - private readonly _esDocField?: ESDocField; constructor(params: PercentileAggParams) { - super(params); - this._esDocField = params.esDocField; + super({ + ...params, + ...{ + aggType: AGG_TYPE.PERCENTILE, + }, + }); this._percentile = params.percentile; } @@ -48,10 +51,6 @@ export class PercentileAggField extends CountAggField implements IESAggField { return `${super.getName()}_${this._percentile}`; } - getRootName(): string { - return this._esDocField ? this._esDocField.getName() : ''; - } - getValueAggDsl(indexPattern: IndexPattern): unknown { const field = getField(indexPattern, this.getRootName()); const dsl: Record = addFieldToDSL({}, field); @@ -60,26 +59,4 @@ export class PercentileAggField extends CountAggField implements IESAggField { percentiles: dsl, }; } - - _getAggType(): AGG_TYPE { - return AGG_TYPE.PERCENTILE; - } - - async getExtendedStatsFieldMetaRequest(): Promise { - return this._esDocField ? await this._esDocField.getExtendedStatsFieldMetaRequest() : null; - } - - async getCategoricalFieldMetaRequest(size: number): Promise { - return this._esDocField ? await this._esDocField.getCategoricalFieldMetaRequest(size) : null; - } - - async getPercentilesFieldMetaRequest(percentiles: number[]): Promise { - return this._esDocField - ? await this._esDocField.getPercentilesFieldMetaRequest(percentiles) - : null; - } - - isValid(): boolean { - return !!this._esDocField; - } } From c294c20ec6689c89dc65d34119dee3ca4ec57c6f Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Wed, 9 Dec 2020 18:30:03 -0500 Subject: [PATCH 50/62] show median --- .../fields/agg/percentile_agg_field.test.ts | 11 ++++++++++ .../fields/agg/percentile_agg_field.ts | 22 ++++++++++++++----- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts index fe4d08a251c0f..14e4fb3412817 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.test.ts @@ -81,4 +81,15 @@ describe('percentile agg field', () => { expect(await field.getLabel()).toEqual('80th agg_label'); }); + + test('label (median)', async () => { + const field = new PercentileAggField({ + ...defaultParams, + label: '', + esDocField: mockEsDocField as ESDocField, + percentile: 50, + }); + + expect(await field.getLabel()).toEqual('median foobar'); + }); }); diff --git a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts index 03991670e1121..d882da4f64cdf 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/percentile_agg_field.ts @@ -5,6 +5,7 @@ */ import { IndexPattern } from 'src/plugins/data/common/index_patterns/index_patterns'; +import { i18n } from '@kbn/i18n'; import { AGG_TYPE } from '../../../../common/constants'; import { IESAggField, CountAggFieldParams } from './agg_field_types'; import { addFieldToDSL, getField } from '../../../../common/elasticsearch_util'; @@ -38,13 +39,22 @@ export class PercentileAggField extends AggField implements IESAggField { } async getLabel(): Promise { + if (this._label) { + return this._label; + } + + if (this._percentile === 50) { + const median = i18n.translate('xpack.maps.fields.percentileMedianLabek', { + defaultMessage: 'median', + }); + return `${median} ${this.getRootName()}`; + } + const suffix = getOrdinalSuffix(this._percentile); - return this._label - ? this._label - : `${this._percentile}${suffix} ${this._source.getAggLabel( - this._getAggType(), - this.getRootName() - )}`; + return `${this._percentile}${suffix} ${this._source.getAggLabel( + this._getAggType(), + this.getRootName() + )}`; } getName() { From 9f11debe74fc16c66401c73027a35058fc2a68ff Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 10 Dec 2020 16:55:41 -0500 Subject: [PATCH 51/62] use number input --- .../metrics_editor/metric_editor.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 2203cc02bbaca..89d1dab389a20 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -12,7 +12,7 @@ import { EuiComboBoxOptionOption, EuiFieldText, EuiFormRow, - EuiRange, + EuiFieldNumber, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -104,9 +104,13 @@ export function MetricEditor({ if (metric.type !== AGG_TYPE.PERCENTILE) { return; } + const percentile = parseInt((e.target as HTMLInputElement).value, 10); + if (typeof percentile !== 'number' || percentile < 0 || percentile > 100) { + return; + } onChange({ ...metric, - percentile: parseInt((e.target as HTMLInputElement).value, 10), + percentile, }); }; const onLabelChange = (e: ChangeEvent) => { @@ -154,14 +158,21 @@ export function MetricEditor({ })} display="columnCompressed" > - From b2e0482b788a17f9d79614d4f4b4971daf00f4ac Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 10 Dec 2020 17:35:25 -0500 Subject: [PATCH 52/62] fix test --- .../public/classes/fields/agg/es_agg_factory.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts index 87b8e6759ba74..abd1527f61ef6 100644 --- a/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts +++ b/x-pack/plugins/maps/public/classes/fields/agg/es_agg_factory.test.ts @@ -8,7 +8,11 @@ import { esAggFieldsFactory } from './es_agg_factory'; import { AGG_TYPE, FIELD_ORIGIN } from '../../../../common/constants'; import { IESAggSource } from '../../sources/es_agg_source'; -const mockEsAggSource = ({} as unknown) as IESAggSource; +const mockEsAggSource = ({ + getAggKey() { + return 'foobar'; + }, +} as unknown) as IESAggSource; describe('esAggFieldsFactory', () => { test('Should only create top terms field when term field is not provided', () => { @@ -37,7 +41,7 @@ describe('esAggFieldsFactory', () => { FIELD_ORIGIN.SOURCE ); expect(fields.length).toBe(1); - expect(fields[0].getName()).toBe('agg_key_50'); + expect(fields[0].getName()).toBe('foobar_50'); }); test('Should create percentile agg fields with param', () => { @@ -47,7 +51,7 @@ describe('esAggFieldsFactory', () => { FIELD_ORIGIN.SOURCE ); expect(fields.length).toBe(1); - expect(fields[0].getName()).toBe('agg_key_90'); + expect(fields[0].getName()).toBe('foobar_90'); }); }); }); From 16f27a3ddf7a8de7e40e69cb929e5221714852d0 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Thu, 10 Dec 2020 17:43:43 -0500 Subject: [PATCH 53/62] order alphabetically --- .../components/metrics_editor/metric_select.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx index 8dbe00c930778..4e77a91958a7d 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx @@ -34,6 +34,12 @@ const AGG_OPTIONS = [ }), value: AGG_TYPE.MIN, }, + { + label: i18n.translate('xpack.maps.metricSelect.percentileDropDownOptionLabel', { + defaultMessage: 'Percentile', + }), + value: AGG_TYPE.PERCENTILE, + }, { label: i18n.translate('xpack.maps.metricSelect.sumDropDownOptionLabel', { defaultMessage: 'Sum', @@ -52,12 +58,6 @@ const AGG_OPTIONS = [ }), value: AGG_TYPE.UNIQUE_COUNT, }, - { - label: i18n.translate('xpack.maps.metricSelect.percentileDropDownOptionLabel', { - defaultMessage: 'Percentile', - }), - value: AGG_TYPE.PERCENTILE, - }, ]; type Props = Omit, 'onChange'> & { From bb96ffdad872984ba8317d780cf532be60581109 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 11:50:23 -0500 Subject: [PATCH 54/62] isolate component --- .../metrics_editor/metric_editor.tsx | 43 ++----- .../metrics_editor/validated_number_input.tsx | 117 ++++++++++++++++++ 2 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 89d1dab389a20..676caeb7928ac 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { ChangeEvent, Fragment, MouseEvent } from 'react'; +import React, { ChangeEvent, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { @@ -22,6 +22,7 @@ import { AggDescriptor } from '../../../common/descriptor_types'; import { AGG_TYPE, DEFAULT_PERCENTILE } from '../../../common/constants'; import { getTermsFields } from '../../index_pattern_util'; import { IFieldType } from '../../../../../../src/plugins/data/public'; +import { ValidatedNumberInput } from './validated_number_input'; function filterFieldsForAgg(fields: IFieldType[], aggType: AGG_TYPE) { if (!fields) { @@ -100,14 +101,10 @@ export function MetricEditor({ }); }; - const onPercentileChange = (e: ChangeEvent | MouseEvent) => { + const onPercentileChange = (percentile: number) => { if (metric.type !== AGG_TYPE.PERCENTILE) { return; } - const percentile = parseInt((e.target as HTMLInputElement).value, 10); - if (typeof percentile !== 'number' || percentile < 0 || percentile > 100) { - return; - } onChange({ ...metric, percentile, @@ -151,31 +148,17 @@ export function MetricEditor({ let percentileSelect; if (metric.type === AGG_TYPE.PERCENTILE) { + const label = i18n.translate('xpack.maps.metricsEditor.selectPercentileLabel', { + defaultMessage: 'Percentile', + }); percentileSelect = ( - - {/* - + ); } diff --git a/x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx b/x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx new file mode 100644 index 0000000000000..de1ae1d4ef019 --- /dev/null +++ b/x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Component, ChangeEvent, MouseEvent } from 'react'; +import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +interface State { + value: number | string; + prevValue: number; + errorMessage: string; + isValid: boolean; +} + +interface Props { + value: number; + min: number; + max: number; + onChange: (value: number) => void; + label: string; +} + +function isNumberValid(value: number | string, min: number, max: number) { + const parsedValue = parseInt(value.toString(), 10); + + if (isNaN(parsedValue)) { + return { + isValid: false, + errorMessage: i18n.translate('xpack.maps.validatedNumberInput.invalidNumberErrorMessage', { + defaultMessage: 'Invalid number', + }), + }; + } + + const isValid = parsedValue >= min && parsedValue <= max; + return { + parsedValue, + isValid, + errorMessage: isValid + ? '' + : i18n.translate('xpack.maps.validatedNumberInput.invalidClampErrorMessage', { + defaultMessage: 'Value must be between {min} and {max}', + values: { + min, + max, + }, + }), + }; +} + +export class ValidatedNumberInput extends Component { + // @ts-expect-error state populated by getDerivedStateFromProps + state: State = {}; + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + if (nextProps.value !== prevState.prevValue) { + const { isValid, errorMessage } = isNumberValid( + nextProps.value, + nextProps.min, + nextProps.max + ); + return { + value: nextProps.value, + prevValue: nextProps.value, + isValid, + errorMessage, + }; + } + + return null; + } + + _submit = _.debounce((value) => { + this.props.onChange(value); + }, 250); + + _onChange = (e: ChangeEvent | MouseEvent) => { + const value = (e.target as HTMLInputElement).value; + const { isValid, errorMessage, parsedValue } = isNumberValid( + value, + this.props.min, + this.props.max + ); + + this.setState({ + value, + errorMessage, + isValid, + }); + + if (isValid) { + this._submit(parsedValue); + } + }; + + render() { + return ( + + + + ); + } +} From d8b7da17227c271490247fdaf2bf7faf6f198226 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 12:09:52 -0500 Subject: [PATCH 55/62] typecheck/move file --- .../public/components/metrics_editor/metric_editor.tsx | 10 ++-------- .../{metrics_editor => }/validated_number_input.tsx | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) rename x-pack/plugins/maps/public/components/{metrics_editor => }/validated_number_input.tsx (99%) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 676caeb7928ac..4417b93fef7ae 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -7,13 +7,7 @@ import React, { ChangeEvent, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { - EuiButtonEmpty, - EuiComboBoxOptionOption, - EuiFieldText, - EuiFormRow, - EuiFieldNumber, -} from '@elastic/eui'; +import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { MetricSelect } from './metric_select'; @@ -22,7 +16,7 @@ import { AggDescriptor } from '../../../common/descriptor_types'; import { AGG_TYPE, DEFAULT_PERCENTILE } from '../../../common/constants'; import { getTermsFields } from '../../index_pattern_util'; import { IFieldType } from '../../../../../../src/plugins/data/public'; -import { ValidatedNumberInput } from './validated_number_input'; +import { ValidatedNumberInput } from '../validated_number_input'; function filterFieldsForAgg(fields: IFieldType[], aggType: AGG_TYPE) { if (!fields) { diff --git a/x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx similarity index 99% rename from x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx rename to x-pack/plugins/maps/public/components/validated_number_input.tsx index de1ae1d4ef019..9d80fc2133449 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -7,6 +7,7 @@ import React, { Component, ChangeEvent, MouseEvent } from 'react'; import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import _ from 'lodash'; interface State { value: number | string; From 0ac90cd846f02040fbe953c62fcd87eb874c5508 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 12:46:48 -0500 Subject: [PATCH 56/62] remove update on prop-change --- .../metrics_editor/metric_editor.tsx | 4 ++- .../components/validated_number_input.tsx | 28 ++++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 4417b93fef7ae..147dc89b41882 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -151,7 +151,9 @@ export function MetricEditor({ max={100} onChange={onPercentileChange} label={label} - value={typeof metric.percentile === 'number' ? metric.percentile : DEFAULT_PERCENTILE} + initialValue={ + typeof metric.percentile === 'number' ? metric.percentile : DEFAULT_PERCENTILE + } /> ); } diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index 9d80fc2133449..3564f1b5924d2 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -11,13 +11,12 @@ import _ from 'lodash'; interface State { value: number | string; - prevValue: number; errorMessage: string; isValid: boolean; } interface Props { - value: number; + initialValue: number; min: number; max: number; onChange: (value: number) => void; @@ -56,22 +55,17 @@ export class ValidatedNumberInput extends Component { // @ts-expect-error state populated by getDerivedStateFromProps state: State = {}; - static getDerivedStateFromProps(nextProps: Props, prevState: State) { - if (nextProps.value !== prevState.prevValue) { - const { isValid, errorMessage } = isNumberValid( - nextProps.value, - nextProps.min, - nextProps.max - ); - return { - value: nextProps.value, - prevValue: nextProps.value, - isValid, - errorMessage, - }; - } + constructor(props: Props) { + super(props); - return null; + const { isValid, errorMessage, parsedValue } = isNumberValid( + props.initialValue, + this.props.min, + this.props.max + ); + this.state.value = isValid ? (parsedValue as number) : props.initialValue; + this.state.errorMessage = errorMessage; + this.state.isValid = isValid; } _submit = _.debounce((value) => { From ca95f4631b526033c3809489b5c34bd2934d33b9 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 12:51:49 -0500 Subject: [PATCH 57/62] add unit test --- .../validated_number_input.test.tsx.snap | 49 +++++++++++++++++++ .../validated_number_input.test.tsx | 25 ++++++++++ 2 files changed, 74 insertions(+) create mode 100644 x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap create mode 100644 x-pack/plugins/maps/public/components/validated_number_input.test.tsx diff --git a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap new file mode 100644 index 0000000000000..255cf4eee5daa --- /dev/null +++ b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with error 1`] = ` + + + +`; + +exports[`should render without error 1`] = ` + + + +`; diff --git a/x-pack/plugins/maps/public/components/validated_number_input.test.tsx b/x-pack/plugins/maps/public/components/validated_number_input.test.tsx new file mode 100644 index 0000000000000..389722c60f17a --- /dev/null +++ b/x-pack/plugins/maps/public/components/validated_number_input.test.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { ValidatedNumberInput } from './validated_number_input'; + +test('should render without error', async () => { + const component = shallow( + {}} initialValue={10} min={0} max={20} label={'foobar'} /> + ); + + expect(component).toMatchSnapshot(); +}); + +test('should render with error', async () => { + const component = shallow( + {}} initialValue={30} min={0} max={20} label={'foobar'} /> + ); + + expect(component).toMatchSnapshot(); +}); From 0ea0b06e8b40b194fd50c9bfbd22d2ed89435191 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 17:25:22 -0500 Subject: [PATCH 58/62] feedback --- .../validated_number_input.test.tsx.snap | 49 ------------------- .../components/validated_number_input.tsx | 28 +++++------ 2 files changed, 14 insertions(+), 63 deletions(-) delete mode 100644 x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap diff --git a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap deleted file mode 100644 index 255cf4eee5daa..0000000000000 --- a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap +++ /dev/null @@ -1,49 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render with error 1`] = ` - - - -`; - -exports[`should render without error 1`] = ` - - - -`; diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index 3564f1b5924d2..e7cce5687bf7b 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -23,15 +23,23 @@ interface Props { label: string; } +function getErrorMessage(min: number, max: number) { + i18n.translate('xpack.maps.validatedNumberInput.invalidClampErrorMessage', { + defaultMessage: 'Must be between {min} and {max}', + values: { + min, + max, + }, + }); +} + function isNumberValid(value: number | string, min: number, max: number) { - const parsedValue = parseInt(value.toString(), 10); + const parsedValue = parseFloat(value.toString()); if (isNaN(parsedValue)) { return { isValid: false, - errorMessage: i18n.translate('xpack.maps.validatedNumberInput.invalidNumberErrorMessage', { - defaultMessage: 'Invalid number', - }), + errorMessage: getErrorMessage(min, max), }; } @@ -39,15 +47,7 @@ function isNumberValid(value: number | string, min: number, max: number) { return { parsedValue, isValid, - errorMessage: isValid - ? '' - : i18n.translate('xpack.maps.validatedNumberInput.invalidClampErrorMessage', { - defaultMessage: 'Value must be between {min} and {max}', - values: { - min, - max, - }, - }), + errorMessage: isValid ? '' : getErrorMessage(min, max), }; } @@ -104,7 +104,7 @@ export class ValidatedNumberInput extends Component { max={this.props.max} value={this.state.value} onChange={this._onChange} - aria-label="number select" + aria-label={`${this.props.label} number input`} /> ); From 02ccab57f69bf3a5977d2ced01187c8f14e5dc41 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Mon, 14 Dec 2020 18:14:14 -0500 Subject: [PATCH 59/62] test fix --- .../validated_number_input.test.tsx.snap | 49 +++++++++++++++++++ .../components/validated_number_input.tsx | 4 +- 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap diff --git a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap new file mode 100644 index 0000000000000..427bb5beb8853 --- /dev/null +++ b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render with error 1`] = ` + + + +`; + +exports[`should render without error 1`] = ` + + + +`; diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index e7cce5687bf7b..e01aab03683cc 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -23,8 +23,8 @@ interface Props { label: string; } -function getErrorMessage(min: number, max: number) { - i18n.translate('xpack.maps.validatedNumberInput.invalidClampErrorMessage', { +function getErrorMessage(min: number, max: number): string { + return i18n.translate('xpack.maps.validatedNumberInput.invalidClampErrorMessage', { defaultMessage: 'Must be between {min} and {max}', values: { min, From c53d81d28bae354c5317bb859560c178382b3ec4 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 15 Dec 2020 09:50:01 -0500 Subject: [PATCH 60/62] feedback --- .../components/validated_number_input.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index e01aab03683cc..ddbc7bece147e 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component, ChangeEvent, MouseEvent } from 'react'; +import React, { Component, ChangeEvent } from 'react'; import { EuiFieldNumber, EuiFormRow } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import _ from 'lodash'; @@ -52,27 +52,27 @@ function isNumberValid(value: number | string, min: number, max: number) { } export class ValidatedNumberInput extends Component { - // @ts-expect-error state populated by getDerivedStateFromProps - state: State = {}; - constructor(props: Props) { super(props); - const { isValid, errorMessage, parsedValue } = isNumberValid( + const { isValid, errorMessage } = isNumberValid( props.initialValue, this.props.min, this.props.max ); - this.state.value = isValid ? (parsedValue as number) : props.initialValue; - this.state.errorMessage = errorMessage; - this.state.isValid = isValid; + + this.state = { + value: props.initialValue, + errorMessage, + isValid, + }; } _submit = _.debounce((value) => { this.props.onChange(value); }, 250); - _onChange = (e: ChangeEvent | MouseEvent) => { + _onChange = (e: ChangeEvent) => { const value = (e.target as HTMLInputElement).value; const { isValid, errorMessage, parsedValue } = isNumberValid( value, From b7e8b73180bf6ebd32eb9e2dedaae517ab6f41a4 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 15 Dec 2020 11:50:16 -0500 Subject: [PATCH 61/62] status --- .../plugins/maps/public/components/validated_number_input.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/components/validated_number_input.tsx b/x-pack/plugins/maps/public/components/validated_number_input.tsx index ddbc7bece147e..a79faa73ced04 100644 --- a/x-pack/plugins/maps/public/components/validated_number_input.tsx +++ b/x-pack/plugins/maps/public/components/validated_number_input.tsx @@ -73,7 +73,7 @@ export class ValidatedNumberInput extends Component { }, 250); _onChange = (e: ChangeEvent) => { - const value = (e.target as HTMLInputElement).value; + const value = e.target.value; const { isValid, errorMessage, parsedValue } = isNumberValid( value, this.props.min, @@ -100,6 +100,7 @@ export class ValidatedNumberInput extends Component { display="columnCompressed" > Date: Tue, 15 Dec 2020 13:24:01 -0500 Subject: [PATCH 62/62] update snapshot --- .../__snapshots__/validated_number_input.test.tsx.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap index 427bb5beb8853..0ae98e2fd4508 100644 --- a/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap +++ b/x-pack/plugins/maps/public/components/__snapshots__/validated_number_input.test.tsx.snap @@ -18,6 +18,7 @@ exports[`should render with error 1`] = ` >