From 0157d7e4eb9356c9223dfc660c0a0fd750384cbb Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Fri, 15 May 2020 14:06:06 -0400 Subject: [PATCH] [Maps] Get number of categories from palette (#66454) --- .../descriptor_types/descriptor_types.d.ts | 1 + .../maps/public/classes/fields/field.ts | 1 + .../dynamic_icon_property.test.tsx.snap | 78 +++++++++++++++++++ .../vector/properties/__tests__/test_util.ts | 75 ++++++++++++++++++ .../properties/dynamic_color_property.test.js | 61 +-------------- .../properties/dynamic_icon_property.js | 5 ++ .../properties/dynamic_icon_property.test.tsx | 61 +++++++++++++++ .../properties/dynamic_style_property.js | 3 +- 8 files changed, 225 insertions(+), 60 deletions(-) create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/properties/__snapshots__/dynamic_icon_property.test.tsx.snap create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/properties/__tests__/test_util.ts create mode 100644 x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx diff --git a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts index 80e417f9dfa62b..4bdafcabaad06f 100644 --- a/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts +++ b/x-pack/plugins/maps/common/descriptor_types/descriptor_types.d.ts @@ -115,6 +115,7 @@ export type JoinDescriptor = { // todo : this union type is incompatible with dynamic extensibility of sources. // Reconsider using SourceDescriptor in type signatures for top-level classes export type SourceDescriptor = + | AbstractSourceDescriptor | XYZTMSSourceDescriptor | WMSSourceDescriptor | KibanaTilemapSourceDescriptor diff --git a/x-pack/plugins/maps/public/classes/fields/field.ts b/x-pack/plugins/maps/public/classes/fields/field.ts index 539d0ab4d6ade1..04daedc59c0324 100644 --- a/x-pack/plugins/maps/public/classes/fields/field.ts +++ b/x-pack/plugins/maps/public/classes/fields/field.ts @@ -20,6 +20,7 @@ export interface IField { isValid(): boolean; getOrdinalFieldMetaRequest(): Promise; getCategoricalFieldMetaRequest(size: number): Promise; + supportsFieldMeta(): boolean; } export class AbstractField implements IField { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/__snapshots__/dynamic_icon_property.test.tsx.snap b/x-pack/plugins/maps/public/classes/styles/vector/properties/__snapshots__/dynamic_icon_property.test.tsx.snap new file mode 100644 index 00000000000000..057907353d68ab --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/__snapshots__/dynamic_icon_property.test.tsx.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should render categorical legend with breaks 1`] = ` +
+ + + + + + Other + + } + styleName="icon" + symbolId="square" + /> + + + + + + + + foobar_label + + + + + + +
+`; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/__tests__/test_util.ts b/x-pack/plugins/maps/public/classes/styles/vector/properties/__tests__/test_util.ts new file mode 100644 index 00000000000000..1c478bb85ccc7e --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/__tests__/test_util.ts @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// eslint-disable-next-line max-classes-per-file +import { FIELD_ORIGIN } from '../../../../../../common/constants'; +import { StyleMeta } from '../../style_meta'; +import { + CategoryFieldMeta, + GeometryTypes, + RangeFieldMeta, + StyleMetaDescriptor, +} from '../../../../../../common/descriptor_types'; +import { AbstractField, IField } from '../../../../fields/field'; + +class MockField extends AbstractField { + async getLabel(): Promise { + return this.getName() + '_label'; + } + supportsFieldMeta(): boolean { + return true; + } +} + +export const mockField: IField = new MockField({ + fieldName: 'foobar', + origin: FIELD_ORIGIN.SOURCE, +}); + +class MockStyle { + getStyleMeta(): StyleMeta { + const geomTypes: GeometryTypes = { + isPointsOnly: false, + isLinesOnly: false, + isPolygonsOnly: false, + }; + const rangeFieldMeta: RangeFieldMeta = { min: 0, max: 100, delta: 100 }; + const catFieldMeta: CategoryFieldMeta = { + categories: [ + { + key: 'US', + count: 10, + }, + { + key: 'CN', + count: 8, + }, + ], + }; + + const styleMetaDescriptor: StyleMetaDescriptor = { + geometryTypes: geomTypes, + fieldMeta: { + foobar: { + range: rangeFieldMeta, + categories: catFieldMeta, + }, + }, + }; + + return new StyleMeta(styleMetaDescriptor); + } +} + +export class MockLayer { + getStyle() { + return new MockStyle(); + } + + getDataRequest() { + return null; + } +} diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.js b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.js index b19c25b369848c..f4c2b8d9260755 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.test.js @@ -15,65 +15,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import { DynamicColorProperty } from './dynamic_color_property'; -import { StyleMeta } from '../style_meta'; -import { COLOR_MAP_TYPE, FIELD_ORIGIN, VECTOR_STYLES } from '../../../../../common/constants'; - -const mockField = { - async getLabel() { - return 'foobar_label'; - }, - getName() { - return 'foobar'; - }, - getRootName() { - return 'foobar'; - }, - getOrigin() { - return FIELD_ORIGIN.SOURCE; - }, - supportsFieldMeta() { - return true; - }, -}; - -class MockStyle { - getStyleMeta() { - return new StyleMeta({ - geometryTypes: { - isPointsOnly: false, - isLinesOnly: false, - isPolygonsOnly: false, - }, - fieldMeta: { - foobar: { - range: { min: 0, max: 100 }, - categories: { - categories: [ - { - key: 'US', - count: 10, - }, - { - key: 'CN', - count: 8, - }, - ], - }, - }, - }, - }); - } -} - -class MockLayer { - getStyle() { - return new MockStyle(); - } - - getDataRequest() { - return null; - } -} +import { COLOR_MAP_TYPE, VECTOR_STYLES } from '../../../../../common/constants'; +import { mockField, MockLayer } from './__tests__/test_util'; const makeProperty = (options, field = mockField) => { return new DynamicColorProperty(options, VECTOR_STYLES.LINE_COLOR, field, new MockLayer(), () => { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.js b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.js index 05e2ad06842cea..27c4fca7d701d5 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.js @@ -29,6 +29,11 @@ export class DynamicIconProperty extends DynamicStyleProperty { return true; } + getNumberOfCategories() { + const palette = getIconPalette(this._options.iconPaletteId); + return palette ? palette.length : 0; + } + syncIconWithMb(symbolLayerId, mbMap, iconPixelSize) { if (this._isIconDynamicConfigComplete()) { mbMap.setLayoutProperty( diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx new file mode 100644 index 00000000000000..c2719432130278 --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_icon_property.test.tsx @@ -0,0 +1,61 @@ +/* + * 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. + */ + +// eslint-disable-next-line max-classes-per-file +import { shallow } from 'enzyme'; + +jest.mock('ui/new_platform'); +jest.mock('../components/vector_style_editor', () => ({ + VectorStyleEditor: () => { + return
mockVectorStyleEditor
; + }, +})); + +import React from 'react'; +import { VECTOR_STYLES } from '../../../../../common/constants'; +// @ts-ignore +import { DynamicIconProperty } from './dynamic_icon_property'; +import { mockField, MockLayer } from './__tests__/test_util'; +import { IconDynamicOptions } from '../../../../../common/descriptor_types'; +import { IField } from '../../../fields/field'; + +const makeProperty = (options: Partial, field: IField = mockField) => { + return new DynamicIconProperty( + { ...options, fieldMetaOptions: { isEnabled: false } }, + VECTOR_STYLES.ICON, + field, + new MockLayer(), + () => { + return (x: string) => x + '_format'; + } + ); +}; + +describe('DynamicIconProperty', () => { + it('should derive category number from palettes', async () => { + const filled = makeProperty({ + iconPaletteId: 'filledShapes', + }); + expect(filled.getNumberOfCategories()).toEqual(6); + const hollow = makeProperty({ + iconPaletteId: 'hollowShapes', + }); + expect(hollow.getNumberOfCategories()).toEqual(5); + }); +}); + +test('Should render categorical legend with breaks', async () => { + const iconStyle = makeProperty({ + iconPaletteId: 'filledShapes', + }); + + const legendRow = iconStyle.renderLegendDetailRow({ isPointsOnly: true, isLinesOnly: false }); + const component = shallow(legendRow); + await new Promise(resolve => process.nextTick(resolve)); + component.update(); + + expect(component).toMatchSnapshot(); +}); diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js index 451a79dd3864aa..56a461a3bb147c 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.js @@ -148,7 +148,8 @@ export class DynamicStyleProperty extends AbstractStyleProperty { if (this.isOrdinal()) { return this._field.getOrdinalFieldMetaRequest(); } else if (this.isCategorical()) { - return this._field.getCategoricalFieldMetaRequest(this.getNumberOfCategories()); + const numberOfCategories = this.getNumberOfCategories(); + return this._field.getCategoricalFieldMetaRequest(numberOfCategories); } else { return null; }