From 891e27eb1f654889ad02703003e7b6e0ff3116e1 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 5 May 2020 12:38:52 -0600 Subject: [PATCH] [Maps] observability real user monitoring solution layer (#64949) * [Maps] observability real user monitoring solution layer * make stateful component * rename RUM to observability * layer select * metrics select * display select * clean up * create cholopleth map layer descriptor * get styling working * fix unique count agg * create geo grid source * render as heatmap * clusters * tslint errors * last tslint fix * only show card when APM index exists * layer label * clean up * fix getLayerWizards * add parans * review feedback * add cluster labels * use green to red ramp * tslint fix Co-authored-by: Elastic Machine --- x-pack/plugins/maps/common/constants.ts | 1 + .../descriptor_types/descriptor_types.d.ts | 1 + .../{get_join_key.ts => get_agg_key.ts} | 15 +- .../maps/common/migrations/join_agg_key.ts | 2 +- .../public/connected_components/_index.scss | 2 +- .../_source_select.scss => _index.scss} | 0 .../layer_addpanel/layer_wizard_select.tsx | 67 ++++ .../layer_addpanel/source_select/_index.scss | 1 - .../source_select/source_select.js | 41 --- .../layer_addpanel/view.js | 8 +- .../public/layers/layer_wizard_registry.ts | 22 +- .../maps/public/layers/load_layer_wizards.ts | 6 +- .../create_layer_descriptor.test.ts | 336 ++++++++++++++++++ .../observability/create_layer_descriptor.ts | 270 ++++++++++++++ .../observability/display_select.tsx | 70 ++++ .../solution_layers/observability/index.ts | 7 + .../observability/layer_select.tsx | 54 +++ .../observability/metric_select.tsx | 89 +++++ .../observability_layer_template.tsx | 82 +++++ .../observability_layer_wizard.tsx | 33 ++ .../sources/es_agg_source/es_agg_source.js | 14 +- .../es_geo_grid_source/es_geo_grid_source.js | 9 +- .../sources/es_search_source/scaling_form.tsx | 10 +- .../sources/es_term_source/es_term_source.js | 11 +- .../kibana_base_map_layer_wizard.tsx | 2 +- .../maps/public/layers/vector_layer.d.ts | 3 +- 26 files changed, 1075 insertions(+), 81 deletions(-) rename x-pack/plugins/maps/common/{get_join_key.ts => get_agg_key.ts} (62%) rename x-pack/plugins/maps/public/connected_components/layer_addpanel/{source_select/_source_select.scss => _index.scss} (100%) create mode 100644 x-pack/plugins/maps/public/connected_components/layer_addpanel/layer_wizard_select.tsx delete mode 100644 x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss delete mode 100644 x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.test.ts create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.ts create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/display_select.tsx create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/index.ts create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/layer_select.tsx create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/metric_select.tsx create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_template.tsx create mode 100644 x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_wizard.tsx diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index e95fe9500746c..139f9e88094e0 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -57,6 +57,7 @@ export enum SOURCE_TYPES { ES_GEO_GRID = 'ES_GEO_GRID', ES_SEARCH = 'ES_SEARCH', ES_PEW_PEW = 'ES_PEW_PEW', + ES_TERM_SOURCE = 'ES_TERM_SOURCE', EMS_XYZ = 'EMS_XYZ', // identifies a custom TMS source. Name is a little unfortunate. WMS = 'WMS', KIBANA_TILEMAP = 'KIBANA_TILEMAP', 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 6980f14d0788a..a9a9fa17c41fc 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 @@ -71,6 +71,7 @@ export type ESPewPewSourceDescriptor = AbstractESAggSourceDescriptor & { export type ESTermSourceDescriptor = AbstractESAggSourceDescriptor & { indexPatternTitle: string; term: string; // term field name + whereQuery?: Query; }; export type KibanaRegionmapSourceDescriptor = AbstractSourceDescriptor & { diff --git a/x-pack/plugins/maps/common/get_join_key.ts b/x-pack/plugins/maps/common/get_agg_key.ts similarity index 62% rename from x-pack/plugins/maps/common/get_join_key.ts rename to x-pack/plugins/maps/common/get_agg_key.ts index f1ee95126b9a9..19c39b4dfa6bd 100644 --- a/x-pack/plugins/maps/common/get_join_key.ts +++ b/x-pack/plugins/maps/common/get_agg_key.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AGG_DELIMITER, AGG_TYPE, JOIN_FIELD_NAME_PREFIX } from './constants'; +import { AGG_DELIMITER, AGG_TYPE, COUNT_PROP_NAME, JOIN_FIELD_NAME_PREFIX } from './constants'; -// function in common since its needed by migration export function getJoinAggKey({ aggType, aggFieldName, @@ -15,8 +14,18 @@ export function getJoinAggKey({ aggType: AGG_TYPE; aggFieldName?: string; rightSourceId: string; -}) { +}): string { const metricKey = aggType !== AGG_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${aggFieldName}` : aggType; return `${JOIN_FIELD_NAME_PREFIX}${metricKey}__${rightSourceId}`; } + +export function getSourceAggKey({ + aggType, + aggFieldName, +}: { + aggType: AGG_TYPE; + aggFieldName?: string; +}): string { + return aggType !== AGG_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${aggFieldName}` : COUNT_PROP_NAME; +} 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 97b9ee4692c25..92e3172f218b9 100644 --- a/x-pack/plugins/maps/common/migrations/join_agg_key.ts +++ b/x-pack/plugins/maps/common/migrations/join_agg_key.ts @@ -13,7 +13,7 @@ import { LAYER_TYPE, VECTOR_STYLES, } from '../constants'; -import { getJoinAggKey } from '../get_join_key'; +import { getJoinAggKey } from '../get_agg_key'; import { AggDescriptor, JoinDescriptor, diff --git a/x-pack/plugins/maps/public/connected_components/_index.scss b/x-pack/plugins/maps/public/connected_components/_index.scss index 83042ae1d586c..a961e652046a6 100644 --- a/x-pack/plugins/maps/public/connected_components/_index.scss +++ b/x-pack/plugins/maps/public/connected_components/_index.scss @@ -1,5 +1,5 @@ @import 'gis_map/gis_map'; -@import 'layer_addpanel/source_select/index'; +@import 'layer_addpanel/index'; @import 'layer_panel/index'; @import 'widget_overlay/index'; @import 'toolbar_overlay/index'; diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss b/x-pack/plugins/maps/public/connected_components/layer_addpanel/_index.scss similarity index 100% rename from x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_source_select.scss rename to x-pack/plugins/maps/public/connected_components/layer_addpanel/_index.scss diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/layer_wizard_select.tsx b/x-pack/plugins/maps/public/connected_components/layer_addpanel/layer_wizard_select.tsx new file mode 100644 index 0000000000000..0359ed2c6269d --- /dev/null +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/layer_wizard_select.tsx @@ -0,0 +1,67 @@ +/* + * 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 _ from 'lodash'; +import React, { Component, Fragment } from 'react'; +import { EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; +import { getLayerWizards, LayerWizard } from '../../layers/layer_wizard_registry'; + +interface Props { + onSelect: (layerWizard: LayerWizard) => void; +} + +interface State { + layerWizards: LayerWizard[]; +} + +export class LayerWizardSelect extends Component { + private _isMounted: boolean = false; + + state = { + layerWizards: [], + }; + + componentDidMount() { + this._isMounted = true; + this._loadLayerWizards(); + } + + componentWillUnmount() { + this._isMounted = false; + } + + async _loadLayerWizards() { + const layerWizards = await getLayerWizards(); + if (this._isMounted) { + this.setState({ layerWizards }); + } + } + + render() { + return this.state.layerWizards.map((layerWizard: LayerWizard) => { + const icon = layerWizard.icon ? : undefined; + + const onClick = () => { + this.props.onSelect(layerWizard); + }; + + return ( + + + + + ); + }); + } +} diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss deleted file mode 100644 index 8ae6970315e13..0000000000000 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@import 'source_select'; diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js deleted file mode 100644 index 82df9237e6ed3..0000000000000 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React, { Fragment } from 'react'; - -import { getLayerWizards } from '../../../layers/layer_wizard_registry'; -import { EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; -import _ from 'lodash'; - -export function SourceSelect({ updateSourceSelection }) { - const sourceCards = getLayerWizards().map(layerWizard => { - const icon = layerWizard.icon ? : null; - - const onClick = () => { - updateSourceSelection({ - layerWizard: layerWizard, - isIndexingSource: !!layerWizard.isIndexingSource, - }); - }; - - return ( - - - - - ); - }); - - return {sourceCards}; -} diff --git a/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js index 127b99d730db5..730e58a107aad 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js +++ b/x-pack/plugins/maps/public/connected_components/layer_addpanel/view.js @@ -5,7 +5,7 @@ */ import React, { Component, Fragment } from 'react'; -import { SourceSelect } from './source_select/source_select'; +import { LayerWizardSelect } from './layer_wizard_select'; import { FlyoutFooter } from './flyout_footer'; import { ImportEditor } from './import_editor'; import { EuiButtonEmpty, EuiPanel, EuiTitle, EuiFlyoutHeader, EuiSpacer } from '@elastic/eui'; @@ -80,8 +80,8 @@ export class AddLayerPanel extends Component { this.props.removeTransientLayer(); }; - _onSourceSelectionChange = ({ layerWizard, isIndexingSource }) => { - this.setState({ layerWizard, importView: isIndexingSource }); + _onWizardSelect = layerWizard => { + this.setState({ layerWizard, importView: !!layerWizard.isIndexingSource }); }; _layerAddHandler = () => { @@ -100,7 +100,7 @@ export class AddLayerPanel extends Component { _renderPanelBody() { if (!this.state.layerWizard) { - return ; + return ; } const backButton = this.props.isIndexingTriggered ? null : ( diff --git a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts index 7715541b1c52d..f866fc10b1f47 100644 --- a/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts +++ b/x-pack/plugins/maps/public/layers/layer_wizard_registry.ts @@ -20,7 +20,7 @@ export type RenderWizardArguments = { }; export type LayerWizard = { - checkVisibility?: () => boolean; + checkVisibility?: () => Promise; description: string; icon: string; isIndexingSource?: boolean; @@ -31,11 +31,23 @@ export type LayerWizard = { const registry: LayerWizard[] = []; export function registerLayerWizard(layerWizard: LayerWizard) { - registry.push(layerWizard); + registry.push({ + checkVisibility: async () => { + return true; + }, + ...layerWizard, + }); } -export function getLayerWizards(): LayerWizard[] { - return registry.filter(layerWizard => { - return layerWizard.checkVisibility ? layerWizard.checkVisibility() : true; +export async function getLayerWizards(): Promise { + const promises = registry.map(async layerWizard => { + return { + ...layerWizard, + // @ts-ignore + isVisible: await layerWizard.checkVisibility(), + }; + }); + return (await Promise.all(promises)).filter(({ isVisible }) => { + return isVisible; }); } diff --git a/x-pack/plugins/maps/public/layers/load_layer_wizards.ts b/x-pack/plugins/maps/public/layers/load_layer_wizards.ts index 0b83f3bbdc613..098ff51791d79 100644 --- a/x-pack/plugins/maps/public/layers/load_layer_wizards.ts +++ b/x-pack/plugins/maps/public/layers/load_layer_wizards.ts @@ -25,17 +25,19 @@ import { tmsLayerWizardConfig } from './sources/xyz_tms_source'; // @ts-ignore import { wmsLayerWizardConfig } from './sources/wms_source'; import { mvtVectorSourceWizardConfig } from './sources/mvt_single_layer_vector_source'; -// @ts-ignore +import { ObservabilityLayerWizardConfig } from './solution_layers/observability'; import { getInjectedVarFunc } from '../kibana_services'; -// Registration order determines display order let registered = false; export function registerLayerWizards() { if (registered) { return; } + + // Registration order determines display order // @ts-ignore registerLayerWizard(uploadLayerWizardConfig); + registerLayerWizard(ObservabilityLayerWizardConfig); // @ts-ignore registerLayerWizard(esDocumentsLayerWizardConfig); // @ts-ignore diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.test.ts b/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.test.ts new file mode 100644 index 0000000000000..6c0b6cdc39b85 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.test.ts @@ -0,0 +1,336 @@ +/* + * 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. + */ + +jest.mock('../../../kibana_services', () => { + const mockUiSettings = { + get: () => { + return undefined; + }, + }; + return { + getUiSettings: () => { + return mockUiSettings; + }, + }; +}); + +jest.mock('uuid/v4', () => { + return function() { + return '12345'; + }; +}); + +import { createLayerDescriptor } from './create_layer_descriptor'; +import { OBSERVABILITY_LAYER_TYPE } from './layer_select'; +import { OBSERVABILITY_METRIC_TYPE } from './metric_select'; +import { DISPLAY } from './display_select'; + +describe('createLayerDescriptor', () => { + test('Should create vector layer descriptor with join when displayed as choropleth', () => { + const layerDescriptor = createLayerDescriptor({ + layer: OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE, + metric: OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION, + display: DISPLAY.CHOROPLETH, + }); + + expect(layerDescriptor).toEqual({ + __dataRequests: [], + alpha: 0.75, + id: '12345', + joins: [ + { + leftField: 'iso2', + right: { + id: '12345', + indexPatternId: 'apm_static_index_pattern_id', + indexPatternTitle: 'apm-*', + metrics: [ + { + field: 'transaction.duration.us', + type: 'avg', + }, + ], + term: 'client.geo.country_iso_code', + type: 'ES_TERM_SOURCE', + whereQuery: { + language: 'kuery', + query: 'processor.event:"transaction"', + }, + }, + }, + ], + label: '[Performance] Duration', + maxZoom: 24, + minZoom: 0, + sourceDescriptor: { + id: 'world_countries', + tooltipProperties: ['name', 'iso2'], + type: 'EMS_FILE', + }, + style: { + isTimeAware: true, + properties: { + fillColor: { + options: { + color: 'Green to Red', + colorCategory: 'palette_0', + field: { + name: '__kbnjoin__avg_of_transaction.duration.us__12345', + origin: 'join', + }, + fieldMetaOptions: { + isEnabled: true, + sigma: 3, + }, + type: 'ORDINAL', + }, + type: 'DYNAMIC', + }, + icon: { + options: { + value: 'marker', + }, + type: 'STATIC', + }, + iconOrientation: { + options: { + orientation: 0, + }, + type: 'STATIC', + }, + iconSize: { + options: { + size: 6, + }, + type: 'STATIC', + }, + labelText: { + options: { + value: '', + }, + type: 'STATIC', + }, + labelBorderColor: { + options: { + color: '#FFFFFF', + }, + type: 'STATIC', + }, + labelBorderSize: { + options: { + size: 'SMALL', + }, + }, + labelColor: { + options: { + color: '#000000', + }, + type: 'STATIC', + }, + labelSize: { + options: { + size: 14, + }, + type: 'STATIC', + }, + lineColor: { + options: { + color: '#3d3d3d', + }, + type: 'STATIC', + }, + lineWidth: { + options: { + size: 1, + }, + type: 'STATIC', + }, + symbolizeAs: { + options: { + value: 'circle', + }, + }, + }, + type: 'VECTOR', + }, + type: 'VECTOR', + visible: true, + }); + }); + + test('Should create heatmap layer descriptor when displayed as heatmap', () => { + const layerDescriptor = createLayerDescriptor({ + layer: OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE, + metric: OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION, + display: DISPLAY.HEATMAP, + }); + expect(layerDescriptor).toEqual({ + __dataRequests: [], + alpha: 0.75, + id: '12345', + joins: [], + label: '[Performance] Duration', + maxZoom: 24, + minZoom: 0, + query: { + language: 'kuery', + query: 'processor.event:"transaction"', + }, + sourceDescriptor: { + geoField: 'client.geo.location', + id: '12345', + indexPatternId: 'apm_static_index_pattern_id', + metrics: [ + { + field: 'transaction.duration.us', + type: 'avg', + }, + ], + requestType: 'heatmap', + resolution: 'MOST_FINE', + type: 'ES_GEO_GRID', + }, + style: { + colorRampName: 'theclassic', + type: 'HEATMAP', + }, + type: 'HEATMAP', + visible: true, + }); + }); + + test('Should create vector layer descriptor when displayed as clusters', () => { + const layerDescriptor = createLayerDescriptor({ + layer: OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE, + metric: OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION, + display: DISPLAY.CLUSTERS, + }); + expect(layerDescriptor).toEqual({ + __dataRequests: [], + alpha: 0.75, + id: '12345', + joins: [], + label: '[Performance] Duration', + maxZoom: 24, + minZoom: 0, + query: { + language: 'kuery', + query: 'processor.event:"transaction"', + }, + sourceDescriptor: { + geoField: 'client.geo.location', + id: '12345', + indexPatternId: 'apm_static_index_pattern_id', + metrics: [ + { + field: 'transaction.duration.us', + type: 'avg', + }, + ], + requestType: 'point', + resolution: 'MOST_FINE', + type: 'ES_GEO_GRID', + }, + style: { + isTimeAware: true, + properties: { + fillColor: { + options: { + color: 'Green to Red', + colorCategory: 'palette_0', + field: { + name: 'avg_of_transaction.duration.us', + origin: 'source', + }, + fieldMetaOptions: { + isEnabled: true, + sigma: 3, + }, + type: 'ORDINAL', + }, + type: 'DYNAMIC', + }, + icon: { + options: { + value: 'marker', + }, + type: 'STATIC', + }, + iconOrientation: { + options: { + orientation: 0, + }, + type: 'STATIC', + }, + iconSize: { + options: { + field: { + name: 'avg_of_transaction.duration.us', + origin: 'source', + }, + fieldMetaOptions: { + isEnabled: true, + sigma: 3, + }, + maxSize: 32, + minSize: 7, + }, + type: 'DYNAMIC', + }, + labelText: { + options: { + value: '', + }, + type: 'STATIC', + }, + labelBorderColor: { + options: { + color: '#FFFFFF', + }, + type: 'STATIC', + }, + labelBorderSize: { + options: { + size: 'SMALL', + }, + }, + labelColor: { + options: { + color: '#000000', + }, + type: 'STATIC', + }, + labelSize: { + options: { + size: 14, + }, + type: 'STATIC', + }, + lineColor: { + options: { + color: '#3d3d3d', + }, + type: 'STATIC', + }, + lineWidth: { + options: { + size: 1, + }, + type: 'STATIC', + }, + symbolizeAs: { + options: { + value: 'circle', + }, + }, + }, + type: 'VECTOR', + }, + type: 'VECTOR', + visible: true, + }); + }); +}); diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.ts b/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.ts new file mode 100644 index 0000000000000..a59122d7d6309 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/create_layer_descriptor.ts @@ -0,0 +1,270 @@ +/* + * 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 uuid from 'uuid/v4'; +import { i18n } from '@kbn/i18n'; +import { + AggDescriptor, + ColorDynamicOptions, + LabelDynamicOptions, + LayerDescriptor, + SizeDynamicOptions, + StylePropertyField, + VectorStylePropertiesDescriptor, +} from '../../../../common/descriptor_types'; +import { + AGG_TYPE, + COLOR_MAP_TYPE, + FIELD_ORIGIN, + GRID_RESOLUTION, + RENDER_AS, + SOURCE_TYPES, + STYLE_TYPE, + VECTOR_STYLES, +} from '../../../../common/constants'; +import { getJoinAggKey, getSourceAggKey } from '../../../../common/get_agg_key'; +import { OBSERVABILITY_LAYER_TYPE } from './layer_select'; +import { OBSERVABILITY_METRIC_TYPE } from './metric_select'; +import { DISPLAY } from './display_select'; +import { VectorStyle } from '../../styles/vector/vector_style'; +// @ts-ignore +import { EMSFileSource } from '../../sources/ems_file_source'; +// @ts-ignore +import { ESGeoGridSource } from '../../sources/es_geo_grid_source'; +import { VectorLayer } from '../../vector_layer'; +// @ts-ignore +import { HeatmapLayer } from '../../heatmap_layer'; +import { getDefaultDynamicProperties } from '../../styles/vector/vector_style_defaults'; + +// redefining APM constant to avoid making maps app depend on APM plugin +export const APM_INDEX_PATTERN_ID = 'apm_static_index_pattern_id'; + +const defaultDynamicProperties = getDefaultDynamicProperties(); + +function createDynamicFillColorDescriptor( + layer: OBSERVABILITY_LAYER_TYPE, + field: StylePropertyField +) { + return { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.FILL_COLOR]!.options as ColorDynamicOptions), + field, + color: + layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE ? 'Green to Red' : 'Yellow to Red', + type: COLOR_MAP_TYPE.ORDINAL, + }, + }; +} + +function createLayerLabel( + layer: OBSERVABILITY_LAYER_TYPE, + metric: OBSERVABILITY_METRIC_TYPE +): string | null { + let layerName; + if (layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE) { + layerName = i18n.translate('xpack.maps.observability.apmRumPerformanceLayerName', { + defaultMessage: 'Performance', + }); + } else if (layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_TRAFFIC) { + layerName = i18n.translate('xpack.maps.observability.apmRumTrafficLayerName', { + defaultMessage: 'Traffic', + }); + } + + let metricName; + if (metric === OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION) { + metricName = i18n.translate('xpack.maps.observability.durationMetricName', { + defaultMessage: 'Duration', + }); + } else if (metric === OBSERVABILITY_METRIC_TYPE.SLA_PERCENTAGE) { + metricName = i18n.translate('xpack.maps.observability.slaPercentageMetricName', { + defaultMessage: '% Duration of SLA', + }); + } else if (metric === OBSERVABILITY_METRIC_TYPE.COUNT) { + metricName = i18n.translate('xpack.maps.observability.countMetricName', { + defaultMessage: 'Total', + }); + } else if (metric === OBSERVABILITY_METRIC_TYPE.UNIQUE_COUNT) { + metricName = i18n.translate('xpack.maps.observability.uniqueCountMetricName', { + defaultMessage: 'Unique count', + }); + } + + return `[${layerName}] ${metricName}`; +} + +function createAggDescriptor(metric: OBSERVABILITY_METRIC_TYPE): AggDescriptor { + if (metric === OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION) { + return { + type: AGG_TYPE.AVG, + field: 'transaction.duration.us', + }; + } else if (metric === OBSERVABILITY_METRIC_TYPE.SLA_PERCENTAGE) { + return { + type: AGG_TYPE.AVG, + field: 'duration_sla_pct', + }; + } else if (metric === OBSERVABILITY_METRIC_TYPE.UNIQUE_COUNT) { + return { + type: AGG_TYPE.UNIQUE_COUNT, + field: 'transaction.id', + }; + } else { + return { type: AGG_TYPE.COUNT }; + } +} + +// All APM indices match APM index pattern. Need to apply query to filter to specific document types +// https://www.elastic.co/guide/en/kibana/current/apm-settings-kb.html +function createAmpSourceQuery(layer: OBSERVABILITY_LAYER_TYPE) { + // APM transaction documents + let query; + if ( + layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE || + layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_TRAFFIC + ) { + query = 'processor.event:"transaction"'; + } + + return query + ? { + language: 'kuery', + query, + } + : undefined; +} + +function getGeoGridRequestType(display: DISPLAY): RENDER_AS { + if (display === DISPLAY.HEATMAP) { + return RENDER_AS.HEATMAP; + } + + if (display === DISPLAY.GRIDS) { + return RENDER_AS.GRID; + } + + return RENDER_AS.POINT; +} + +export function createLayerDescriptor({ + layer, + metric, + display, +}: { + layer: OBSERVABILITY_LAYER_TYPE | null; + metric: OBSERVABILITY_METRIC_TYPE | null; + display: DISPLAY | null; +}): LayerDescriptor | null { + if (!layer || !metric || !display) { + return null; + } + + const apmSourceQuery = createAmpSourceQuery(layer); + const label = createLayerLabel(layer, metric); + const metricsDescriptor = createAggDescriptor(metric); + + if (display === DISPLAY.CHOROPLETH) { + const joinId = uuid(); + const joinKey = getJoinAggKey({ + aggType: metricsDescriptor.type, + aggFieldName: metricsDescriptor.field ? metricsDescriptor.field : '', + rightSourceId: joinId, + }); + return VectorLayer.createDescriptor({ + label, + joins: [ + { + leftField: 'iso2', + right: { + type: SOURCE_TYPES.ES_TERM_SOURCE, + id: joinId, + indexPatternId: APM_INDEX_PATTERN_ID, + indexPatternTitle: 'apm-*', // TODO look up from APM_OSS.indexPattern + term: 'client.geo.country_iso_code', + metrics: [metricsDescriptor], + whereQuery: apmSourceQuery, + }, + }, + ], + sourceDescriptor: EMSFileSource.createDescriptor({ + id: 'world_countries', + tooltipProperties: ['name', 'iso2'], + }), + style: VectorStyle.createDescriptor({ + [VECTOR_STYLES.FILL_COLOR]: createDynamicFillColorDescriptor(layer, { + name: joinKey, + origin: FIELD_ORIGIN.JOIN, + }), + [VECTOR_STYLES.LINE_COLOR]: { + type: STYLE_TYPE.STATIC, + options: { + color: '#3d3d3d', + }, + }, + }), + }); + } + + const geoGridSourceDescriptor = ESGeoGridSource.createDescriptor({ + indexPatternId: APM_INDEX_PATTERN_ID, + geoField: 'client.geo.location', + metrics: [metricsDescriptor], + requestType: getGeoGridRequestType(display), + resolution: GRID_RESOLUTION.MOST_FINE, + }); + + if (display === DISPLAY.HEATMAP) { + return HeatmapLayer.createDescriptor({ + label, + query: apmSourceQuery, + sourceDescriptor: geoGridSourceDescriptor, + }); + } + + const metricSourceKey = getSourceAggKey({ + aggType: metricsDescriptor.type, + aggFieldName: metricsDescriptor.field, + }); + const metricStyleField = { + name: metricSourceKey, + origin: FIELD_ORIGIN.SOURCE, + }; + + const styleProperties: VectorStylePropertiesDescriptor = { + [VECTOR_STYLES.FILL_COLOR]: createDynamicFillColorDescriptor(layer, metricStyleField), + [VECTOR_STYLES.ICON_SIZE]: { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.ICON_SIZE]!.options as SizeDynamicOptions), + field: metricStyleField, + }, + }, + [VECTOR_STYLES.LINE_COLOR]: { + type: STYLE_TYPE.STATIC, + options: { + color: '#3d3d3d', + }, + }, + }; + + if (metric === OBSERVABILITY_METRIC_TYPE.SLA_PERCENTAGE) { + styleProperties[VECTOR_STYLES.LABEL_TEXT] = { + type: STYLE_TYPE.DYNAMIC, + options: { + ...(defaultDynamicProperties[VECTOR_STYLES.LABEL_TEXT]!.options as LabelDynamicOptions), + field: metricStyleField, + }, + }; + } + + return VectorLayer.createDescriptor({ + label, + query: apmSourceQuery, + sourceDescriptor: geoGridSourceDescriptor, + style: VectorStyle.createDescriptor(styleProperties), + }); +} diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/display_select.tsx b/x-pack/plugins/maps/public/layers/solution_layers/observability/display_select.tsx new file mode 100644 index 0000000000000..2c6d854db2fe9 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/display_select.tsx @@ -0,0 +1,70 @@ +/* + * 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, { ChangeEvent } from 'react'; +import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_LAYER_TYPE } from './layer_select'; + +export enum DISPLAY { + CHOROPLETH = 'CHOROPLETH', + CLUSTERS = 'CLUSTERS', + GRIDS = 'GRIDS', + HEATMAP = 'HEATMAP', +} + +const DISPLAY_OPTIONS = [ + { + value: DISPLAY.CHOROPLETH, + text: i18n.translate('xpack.maps.observability.choroplethLabel', { + defaultMessage: 'World boundaries', + }), + }, + { + value: DISPLAY.CLUSTERS, + text: i18n.translate('xpack.maps.observability.clustersLabel', { + defaultMessage: 'Clusters', + }), + }, + { + value: DISPLAY.GRIDS, + text: i18n.translate('xpack.maps.observability.gridsLabel', { + defaultMessage: 'Grids', + }), + }, + { + value: DISPLAY.HEATMAP, + text: i18n.translate('xpack.maps.observability.heatMapLabel', { + defaultMessage: 'Heat map', + }), + }, +]; + +interface Props { + layer: OBSERVABILITY_LAYER_TYPE | null; + value: DISPLAY; + onChange: (display: DISPLAY) => void; +} + +export function DisplaySelect(props: Props) { + function onChange(event: ChangeEvent) { + props.onChange(event.target.value as DISPLAY); + } + + if (!props.layer) { + return null; + } + + return ( + + + + ); +} diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/index.ts b/x-pack/plugins/maps/public/layers/solution_layers/observability/index.ts new file mode 100644 index 0000000000000..ae6ade86de980 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/index.ts @@ -0,0 +1,7 @@ +/* + * 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 { ObservabilityLayerWizardConfig } from './observability_layer_wizard'; diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/layer_select.tsx b/x-pack/plugins/maps/public/layers/solution_layers/observability/layer_select.tsx new file mode 100644 index 0000000000000..1c03cb419a849 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/layer_select.tsx @@ -0,0 +1,54 @@ +/* + * 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, { ChangeEvent } from 'react'; +import { EuiFormRow, EuiSelect } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export enum OBSERVABILITY_LAYER_TYPE { + APM_RUM_PERFORMANCE = 'APM_RUM_PERFORMANCE', + APM_RUM_TRAFFIC = 'APM_RUM_TRAFFIC', +} + +const OBSERVABILITY_LAYER_OPTIONS = [ + { + value: OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE, + text: i18n.translate('xpack.maps.observability.apmRumPerformanceLabel', { + defaultMessage: 'APM RUM Performance', + }), + }, + { + value: OBSERVABILITY_LAYER_TYPE.APM_RUM_TRAFFIC, + text: i18n.translate('xpack.maps.observability.apmRumTrafficLabel', { + defaultMessage: 'APM RUM Traffic', + }), + }, +]; + +interface Props { + value: OBSERVABILITY_LAYER_TYPE | null; + onChange: (layer: OBSERVABILITY_LAYER_TYPE) => void; +} + +export function LayerSelect(props: Props) { + function onChange(event: ChangeEvent) { + props.onChange(event.target.value as OBSERVABILITY_LAYER_TYPE); + } + + const options = props.value + ? OBSERVABILITY_LAYER_OPTIONS + : [{ value: '', text: '' }, ...OBSERVABILITY_LAYER_OPTIONS]; + + return ( + + + + ); +} diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/metric_select.tsx b/x-pack/plugins/maps/public/layers/solution_layers/observability/metric_select.tsx new file mode 100644 index 0000000000000..8750034f74696 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/metric_select.tsx @@ -0,0 +1,89 @@ +/* + * 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, { ChangeEvent } from 'react'; +import { EuiFormRow, EuiSelect, EuiSelectOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { OBSERVABILITY_LAYER_TYPE } from './layer_select'; + +export enum OBSERVABILITY_METRIC_TYPE { + TRANSACTION_DURATION = 'TRANSACTION_DURATION', + SLA_PERCENTAGE = 'SLA_PERCENTAGE', + COUNT = 'COUNT', + UNIQUE_COUNT = 'UNIQUE_COUNT', +} + +const APM_RUM_PERFORMANCE_METRIC_OPTIONS = [ + { + value: OBSERVABILITY_METRIC_TYPE.TRANSACTION_DURATION, + text: i18n.translate('xpack.maps.observability.transactionDurationLabel', { + defaultMessage: 'Transaction duraction', + }), + }, + { + value: OBSERVABILITY_METRIC_TYPE.SLA_PERCENTAGE, + text: i18n.translate('xpack.maps.observability.slaPercentageLabel', { + defaultMessage: 'SLA percentage', + }), + }, +]; + +const APM_RUM_TRAFFIC_METRIC_OPTIONS = [ + { + value: OBSERVABILITY_METRIC_TYPE.COUNT, + text: i18n.translate('xpack.maps.observability.countLabel', { + defaultMessage: 'Count', + }), + }, + { + value: OBSERVABILITY_METRIC_TYPE.UNIQUE_COUNT, + text: i18n.translate('xpack.maps.observability.uniqueCountLabel', { + defaultMessage: 'Unique count', + }), + }, +]; + +export function getMetricOptionsForLayer(layer: OBSERVABILITY_LAYER_TYPE): EuiSelectOption[] { + if (layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_PERFORMANCE) { + return APM_RUM_PERFORMANCE_METRIC_OPTIONS; + } + + if (layer === OBSERVABILITY_LAYER_TYPE.APM_RUM_TRAFFIC) { + return APM_RUM_TRAFFIC_METRIC_OPTIONS; + } + + return []; +} + +interface Props { + layer: OBSERVABILITY_LAYER_TYPE | null; + value: OBSERVABILITY_METRIC_TYPE | null; + onChange: (metricType: OBSERVABILITY_METRIC_TYPE) => void; +} + +export function MetricSelect(props: Props) { + function onChange(event: ChangeEvent) { + props.onChange(event.target.value as OBSERVABILITY_METRIC_TYPE); + } + + if (!props.layer || !props.value) { + return null; + } + + return ( + + + + ); +} diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_template.tsx b/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_template.tsx new file mode 100644 index 0000000000000..7326f8459b5c7 --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_template.tsx @@ -0,0 +1,82 @@ +/* + * 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, Fragment } from 'react'; +import { RenderWizardArguments } from '../../layer_wizard_registry'; +import { LayerSelect, OBSERVABILITY_LAYER_TYPE } from './layer_select'; +import { getMetricOptionsForLayer, MetricSelect, OBSERVABILITY_METRIC_TYPE } from './metric_select'; +import { DisplaySelect, DISPLAY } from './display_select'; +import { createLayerDescriptor } from './create_layer_descriptor'; + +interface State { + display: DISPLAY; + layer: OBSERVABILITY_LAYER_TYPE | null; + metric: OBSERVABILITY_METRIC_TYPE | null; +} + +export class ObservabilityLayerTemplate extends Component { + state = { + layer: null, + metric: null, + display: DISPLAY.CHOROPLETH, + }; + + _onLayerChange = (layer: OBSERVABILITY_LAYER_TYPE) => { + const newState = { layer, metric: this.state.metric }; + + // Select metric when layer change invalidates selected metric. + const metricOptions = getMetricOptionsForLayer(layer); + const selectedMetricOption = metricOptions.find(option => { + return option.value === this.state.metric; + }); + if (!selectedMetricOption) { + if (metricOptions.length) { + // @ts-ignore + newState.metric = metricOptions[0].value; + } else { + newState.metric = null; + } + } + + this.setState(newState, this._previewLayer); + }; + + _onMetricChange = (metric: OBSERVABILITY_METRIC_TYPE) => { + this.setState({ metric }, this._previewLayer); + }; + + _onDisplayChange = (display: DISPLAY) => { + this.setState({ display }, this._previewLayer); + }; + + _previewLayer() { + this.props.previewLayer( + createLayerDescriptor({ + layer: this.state.layer, + metric: this.state.metric, + display: this.state.display, + }) + ); + } + + render() { + return ( + + + + + + ); + } +} diff --git a/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_wizard.tsx new file mode 100644 index 0000000000000..3fbb3157ae62a --- /dev/null +++ b/x-pack/plugins/maps/public/layers/solution_layers/observability/observability_layer_wizard.tsx @@ -0,0 +1,33 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { LayerWizard, RenderWizardArguments } from '../../layer_wizard_registry'; +import { ObservabilityLayerTemplate } from './observability_layer_template'; +import { APM_INDEX_PATTERN_ID } from './create_layer_descriptor'; +import { getIndexPatternService } from '../../../kibana_services'; + +export const ObservabilityLayerWizardConfig: LayerWizard = { + checkVisibility: async () => { + try { + await getIndexPatternService().get(APM_INDEX_PATTERN_ID); + return true; + } catch (e) { + return false; + } + }, + description: i18n.translate('xpack.maps.observability.desc', { + defaultMessage: 'APM layers', + }), + icon: 'logoObservability', + renderWizard: (renderWizardArguments: RenderWizardArguments) => { + return ; + }, + title: i18n.translate('xpack.maps.observability.title', { + defaultMessage: 'Observability', + }), +}; diff --git a/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js index 58c56fe32f766..22c8293132b42 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_agg_source/es_agg_source.js @@ -7,13 +7,8 @@ import { i18n } from '@kbn/i18n'; import { AbstractESSource } from '../es_source'; import { esAggFieldsFactory } from '../../fields/es_agg_field'; -import { - AGG_DELIMITER, - AGG_TYPE, - COUNT_PROP_LABEL, - COUNT_PROP_NAME, - FIELD_ORIGIN, -} from '../../../../common/constants'; +import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; +import { getSourceAggKey } from '../../../../common/get_agg_key'; export class AbstractESAggSource extends AbstractESSource { constructor(descriptor, inspectorAdapters) { @@ -59,7 +54,10 @@ export class AbstractESAggSource extends AbstractESSource { } getAggKey(aggType, fieldName) { - return aggType !== AGG_TYPE.COUNT ? `${aggType}${AGG_DELIMITER}${fieldName}` : COUNT_PROP_NAME; + return getSourceAggKey({ + aggType, + aggFieldName: fieldName, + }); } getAggLabel(aggType, fieldName) { diff --git a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 17fad2f2e6453..053af4bfebe61 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -35,13 +35,14 @@ export const heatmapTitle = i18n.translate('xpack.maps.source.esGridHeatmapTitle export class ESGeoGridSource extends AbstractESAggSource { static type = SOURCE_TYPES.ES_GEO_GRID; - static createDescriptor({ indexPatternId, geoField, requestType, resolution }) { + static createDescriptor({ indexPatternId, geoField, metrics, requestType, resolution }) { return { type: ESGeoGridSource.type, id: uuid(), - indexPatternId: indexPatternId, - geoField: geoField, - requestType: requestType, + indexPatternId, + geoField, + metrics: metrics ? metrics : [], + requestType, resolution: resolution ? resolution : GRID_RESOLUTION.COARSE, }; } diff --git a/x-pack/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx b/x-pack/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx index d86fc6d4026e6..829c9a1ce439d 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx +++ b/x-pack/plugins/maps/public/layers/sources/es_search_source/scaling_form.tsx @@ -18,9 +18,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; // @ts-ignore import { SingleFieldSelect } from '../../../components/single_field_select'; - -// @ts-ignore -import { indexPatternService } from '../../../kibana_services'; +import { getIndexPatternService } from '../../../kibana_services'; // @ts-ignore import { ValidatedRange } from '../../../components/validated_range'; import { @@ -68,8 +66,10 @@ export class ScalingForm extends Component { async loadIndexSettings() { try { - const indexPattern = await indexPatternService.get(this.props.indexPatternId); - const { maxInnerResultWindow, maxResultWindow } = await loadIndexSettings(indexPattern.title); + const indexPattern = await getIndexPatternService().get(this.props.indexPatternId); + const { maxInnerResultWindow, maxResultWindow } = await loadIndexSettings( + indexPattern!.title + ); if (this._isMounted) { this.setState({ maxInnerResultWindow, maxResultWindow }); } diff --git a/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js index cb07bb0e7d2ed..a6c4afa71dbb2 100644 --- a/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js +++ b/x-pack/plugins/maps/public/layers/sources/es_term_source/es_term_source.js @@ -7,8 +7,13 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { AGG_TYPE, DEFAULT_MAX_BUCKETS_LIMIT, FIELD_ORIGIN } from '../../../../common/constants'; -import { getJoinAggKey } from '../../../../common/get_join_key'; +import { + AGG_TYPE, + DEFAULT_MAX_BUCKETS_LIMIT, + FIELD_ORIGIN, + SOURCE_TYPES, +} from '../../../../common/constants'; +import { getJoinAggKey } from '../../../../common/get_agg_key'; import { ESDocField } from '../../fields/es_doc_field'; import { AbstractESAggSource } from '../es_agg_source'; import { getField, addFieldToDSL, extractPropertiesFromBucket } from '../../util/es_agg_utils'; @@ -30,7 +35,7 @@ export function extractPropertiesMap(rawEsData, countPropertyName) { } export class ESTermSource extends AbstractESAggSource { - static type = 'ES_TERM_SOURCE'; + static type = SOURCE_TYPES.ES_TERM_SOURCE; constructor(descriptor, inspectorAdapters) { super(descriptor, inspectorAdapters); diff --git a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx index 141fabeedd3e5..3b4015641ede9 100644 --- a/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx +++ b/x-pack/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_base_map_layer_wizard.tsx @@ -16,7 +16,7 @@ import { TileLayer } from '../../tile_layer'; import { getKibanaTileMap } from '../../../meta'; export const kibanaBasemapLayerWizardConfig: LayerWizard = { - checkVisibility: () => { + checkVisibility: async () => { const tilemap = getKibanaTileMap(); return !!tilemap.url; }, diff --git a/x-pack/plugins/maps/public/layers/vector_layer.d.ts b/x-pack/plugins/maps/public/layers/vector_layer.d.ts index efc1f3011c687..710b95b045e71 100644 --- a/x-pack/plugins/maps/public/layers/vector_layer.d.ts +++ b/x-pack/plugins/maps/public/layers/vector_layer.d.ts @@ -9,7 +9,6 @@ import { AbstractLayer } from './layer'; import { IVectorSource } from './sources/vector_source'; import { MapFilters, - LayerDescriptor, VectorLayerDescriptor, VectorSourceRequestMeta, } from '../../common/descriptor_types'; @@ -35,7 +34,7 @@ export interface IVectorLayer extends ILayer { export class VectorLayer extends AbstractLayer implements IVectorLayer { protected readonly _style: IVectorStyle; static createDescriptor( - options: Partial, + options: Partial, mapColors?: string[] ): VectorLayerDescriptor;