Skip to content

Commit

Permalink
[Maps] Update style when metrics change (elastic#83586)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasneirynck committed Dec 4, 2020
1 parent 9fd020e commit 8dbd8f7
Show file tree
Hide file tree
Showing 9 changed files with 489 additions and 170 deletions.
Expand Up @@ -254,3 +254,8 @@ export type DynamicStylePropertyOptions =
| LabelDynamicOptions
| OrientationDynamicOptions
| SizeDynamicOptions;

export type DynamicStyleProperties = {
type: STYLE_TYPE.DYNAMIC;
options: DynamicStylePropertyOptions;
};
36 changes: 31 additions & 5 deletions x-pack/plugins/maps/public/actions/layer_actions.ts
Expand Up @@ -45,6 +45,8 @@ 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 { IESAggField } from '../classes/fields/agg';
import { IField } from '../classes/fields/field';

export function trackCurrentLayerState(layerId: string) {
return {
Expand Down Expand Up @@ -274,13 +276,37 @@ export function updateLayerOrder(newLayerOrder: number[]) {
};
}

function updateMetricsProp(layerId: string, value: unknown) {
return async (
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
getState: () => MapStoreState
) => {
const layer = getLayerById(layerId, getState());
const previousFields = await (layer as IVectorLayer).getFields();
await dispatch({
type: UPDATE_SOURCE_PROP,
layerId,
propName: 'metrics',
value,
});
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<MapStoreState, void, AnyAction>) => {
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,
Expand All @@ -290,7 +316,6 @@ export function updateSourceProp(
if (newLayerType) {
dispatch(updateLayerType(layerId, newLayerType));
}
await dispatch(clearMissingStyleProperties(layerId));
dispatch(syncDataForLayerId(layerId));
};
}
Expand Down Expand Up @@ -422,7 +447,7 @@ function removeLayerFromLayerList(layerId: string) {
};
}

export function clearMissingStyleProperties(layerId: string) {
function updateStyleProperties(layerId: string, previousFields: IField[]) {
return async (
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
getState: () => MapStoreState
Expand All @@ -441,8 +466,9 @@ export function clearMissingStyleProperties(layerId: string) {
const {
hasChanges,
nextStyleDescriptor,
} = await (style as IVectorStyle).getDescriptorWithMissingStylePropsRemoved(
} = await (style as IVectorStyle).getDescriptorWithUpdatedStyleProps(
nextFields,
previousFields,
getMapColors(getState())
);
if (hasChanges && nextStyleDescriptor) {
Expand Down Expand Up @@ -485,13 +511,13 @@ export function updateLayerStyleForSelectedLayer(styleDescriptor: StyleDescripto

export function setJoinsForLayer(layer: ILayer, joins: JoinDescriptor[]) {
return async (dispatch: ThunkDispatch<MapStoreState, void, AnyAction>) => {
const previousFields = await (layer as IVectorLayer).getFields();
await dispatch({
type: SET_JOINS,
layer,
joins,
});

await dispatch(clearMissingStyleProperties(layer.getId()));
await dispatch(updateStyleProperties(layer.getId(), previousFields));
dispatch(syncDataForLayerId(layer.getId()));
};
}
Expand Down
Expand Up @@ -97,4 +97,8 @@ export class CountAggField implements IESAggField {
canReadFromGeoJson(): boolean {
return this._canReadFromGeoJson;
}

isEqual(field: IESAggField) {
return field.getName() === this.getName();
}
}
Expand Up @@ -83,4 +83,8 @@ export class TopTermPercentageField implements IESAggField {
canReadFromGeoJson(): boolean {
return this._canReadFromGeoJson;
}

isEqual(field: IESAggField) {
return field.getName() === this.getName();
}
}
5 changes: 5 additions & 0 deletions x-pack/plugins/maps/public/classes/fields/field.ts
Expand Up @@ -32,6 +32,7 @@ export interface IField {
supportsFieldMeta(): boolean;

canReadFromGeoJson(): boolean;
isEqual(field: IField): boolean;
}

export class AbstractField implements IField {
Expand Down Expand Up @@ -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();
}
}
@@ -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 { FIELD_ORIGIN, VECTOR_STYLES } from '../../../../common/constants';
import { createStyleFieldsHelper, StyleFieldsHelper } from './style_fields_helper';
import { AbstractField, IField } 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
): Promise<{
styleFieldHelper: StyleFieldsHelper;
stringField: IField;
numberField: IField;
dateField: IField;
}> {
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.hasFieldForStyle(stringField, styleType)).toEqual(true);
expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true);
expect(styleFieldHelper.hasFieldForStyle(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.hasFieldForStyle(stringField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true);
expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(true);
}
);
});

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.hasFieldForStyle(stringField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(false);
}
);
});

test('Should validate orientation only number types', async () => {
const { styleFieldHelper, stringField, numberField, dateField } = await createHelper(true);

[VECTOR_STYLES.ICON_ORIENTATION].forEach((styleType) => {
expect(styleFieldHelper.hasFieldForStyle(stringField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(true);
expect(styleFieldHelper.hasFieldForStyle(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.hasFieldForStyle(stringField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(numberField, styleType)).toEqual(false);
expect(styleFieldHelper.hasFieldForStyle(dateField, styleType)).toEqual(false);
});
});
});
});
Expand Up @@ -69,6 +69,11 @@ export class StyleFieldsHelper {
this._ordinalFields = ordinalFields;
}

hasFieldForStyle(field: IField, styleName: VECTOR_STYLES): boolean {
const fieldList = this.getFieldsForStyle(styleName);
return fieldList.some((styleField) => field.getName() === styleField.name);
}

getFieldsForStyle(styleName: VECTOR_STYLES): StyleField[] {
switch (styleName) {
case VECTOR_STYLES.ICON_ORIENTATION:
Expand Down

0 comments on commit 8dbd8f7

Please sign in to comment.