diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js index e9ef38e17b188..762409b256286 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/import_editor/view.js @@ -5,13 +5,12 @@ */ import React, { Fragment } from 'react'; -import { GeojsonFileSource } from '../../../layers/sources/client_file_source'; import { EuiSpacer, EuiPanel, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { uploadLayerWizardConfig } from '../../../layers/sources/client_file_source'; export const ImportEditor = ({ clearSource, isIndexingTriggered, ...props }) => { const editorProperties = getEditorProperties({ isIndexingTriggered, ...props }); - const editor = GeojsonFileSource.renderEditor(editorProperties); return ( {isIndexingTriggered ? null : ( @@ -25,7 +24,9 @@ export const ImportEditor = ({ clearSource, isIndexingTriggered, ...props }) => )} - {editor} + + {uploadLayerWizardConfig.renderWizard(editorProperties)} + ); }; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js index 45c508e0d5889..50312b68277fa 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_editor/view.js @@ -5,28 +5,20 @@ */ import React, { Fragment } from 'react'; -import { ALL_SOURCES } from '../../../layers/sources/all_sources'; import { EuiSpacer, EuiPanel, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; export const SourceEditor = ({ clearSource, - sourceType, + layerWizard, isIndexingTriggered, inspectorAdapters, previewLayer, }) => { - const editorProperties = { - onPreviewSource: previewLayer, - inspectorAdapters, - }; - const Source = ALL_SOURCES.find(Source => { - return Source.type === sourceType; - }); - if (!Source) { - throw new Error(`Unexpected source type: ${sourceType}`); + if (!layerWizard) { + return null; } - const editor = Source.renderEditor(editorProperties); + return ( {isIndexingTriggered ? null : ( @@ -40,7 +32,9 @@ export const SourceEditor = ({ )} - {editor} + + {layerWizard.renderWizard({ onPreviewSource: previewLayer, inspectorAdapters })} + ); }; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js index 574a57b1041a0..b34a432bec88c 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/source_select/source_select.js @@ -5,30 +5,33 @@ */ import React, { Fragment } from 'react'; -import { ALL_SOURCES } from '../../../layers/sources/all_sources'; +import { getLayerWizards } from '../../../layers/layer_wizard_registry'; import { EuiTitle, EuiSpacer, EuiCard, EuiIcon } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import _ from 'lodash'; export function SourceSelect({ updateSourceSelection }) { - const sourceCards = ALL_SOURCES.map(Source => { - const icon = Source.icon ? : null; + const sourceCards = getLayerWizards().map(layerWizard => { + const icon = layerWizard.icon ? : null; - const sourceTitle = Source.title; + const onClick = () => { + updateSourceSelection({ + layerWizard: layerWizard, + isIndexingSource: !!layerWizard.isIndexingSource, + }); + }; return ( - + - updateSourceSelection({ type: Source.type, isIndexingSource: Source.isIndexingSource }) - } - description={Source.description} + onClick={onClick} + description={layerWizard.description} layout="horizontal" - data-test-subj={_.camelCase(Source.title)} + data-test-subj={_.camelCase(layerWizard.title)} /> ); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js index 425cc1cae3649..a54df69471aa0 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_addpanel/view.js @@ -14,7 +14,7 @@ import { i18n } from '@kbn/i18n'; export class AddLayerPanel extends Component { state = { - sourceType: null, + layerWizard: null, layer: null, importView: false, layerImportAddReady: false, @@ -35,9 +35,9 @@ export class AddLayerPanel extends Component { } _getPanelDescription() { - const { sourceType, importView, layerImportAddReady } = this.state; + const { layerWizard, importView, layerImportAddReady } = this.state; let panelDescription; - if (!sourceType) { + if (!layerWizard) { panelDescription = i18n.translate('xpack.maps.addLayerPanel.selectSource', { defaultMessage: 'Select source', }); @@ -85,13 +85,13 @@ export class AddLayerPanel extends Component { this.setState({ layer: null, - ...(!keepSourceType ? { sourceType: null, importView: false } : {}), + ...(!keepSourceType ? { layerWizard: null, importView: false } : {}), }); this.props.removeTransientLayer(); }; - _onSourceSelectionChange = ({ type, isIndexingSource }) => { - this.setState({ sourceType: type, importView: isIndexingSource }); + _onSourceSelectionChange = ({ layerWizard, isIndexingSource }) => { + this.setState({ layerWizard, importView: isIndexingSource }); }; _layerAddHandler = () => { @@ -118,8 +118,8 @@ export class AddLayerPanel extends Component { }; _renderAddLayerPanel() { - const { sourceType, importView } = this.state; - if (!sourceType) { + const { layerWizard, importView } = this.state; + if (!layerWizard) { return ; } if (importView) { @@ -134,7 +134,7 @@ export class AddLayerPanel extends Component { return ( ); @@ -148,7 +148,7 @@ export class AddLayerPanel extends Component { return ( void; + inspectorAdapters: unknown; + }): unknown; + title: string; +}; + +const registry: LayerWizard[] = []; + +export function registerLayerWizard(layerWizard: LayerWizard) { + registry.push(layerWizard); +} + +export function getLayerWizards(): LayerWizard[] { + return [...registry]; +} diff --git a/x-pack/legacy/plugins/maps/public/layers/load_layer_wizards.js b/x-pack/legacy/plugins/maps/public/layers/load_layer_wizards.js new file mode 100644 index 0000000000000..d0169165eaa35 --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/load_layer_wizards.js @@ -0,0 +1,30 @@ +/* + * 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 { registerLayerWizard } from './layer_wizard_registry'; +import { uploadLayerWizardConfig } from './sources/client_file_source'; +import { esDocumentsLayerWizardConfig } from './sources/es_search_source'; +import { clustersLayerWizardConfig, heatmapLayerWizardConfig } from './sources/es_geo_grid_source'; +import { point2PointLayerWizardConfig } from './sources/es_pew_pew_source/es_pew_pew_source'; +import { emsBoundariesLayerWizardConfig } from './sources/ems_file_source'; +import { emsBaseMapLayerWizardConfig } from './sources/ems_tms_source'; +import { kibanaRegionMapLayerWizardConfig } from './sources/kibana_regionmap_source'; +import { kibanaBasemapLayerWizardConfig } from './sources/kibana_tilemap_source'; +import { tmsLayerWizardConfig } from './sources/xyz_tms_source'; +import { wmsLayerWizardConfig } from './sources/wms_source'; + +// Registration order determines display order +registerLayerWizard(uploadLayerWizardConfig); +registerLayerWizard(esDocumentsLayerWizardConfig); +registerLayerWizard(clustersLayerWizardConfig); +registerLayerWizard(heatmapLayerWizardConfig); +registerLayerWizard(point2PointLayerWizardConfig); +registerLayerWizard(emsBoundariesLayerWizardConfig); +registerLayerWizard(emsBaseMapLayerWizardConfig); +registerLayerWizard(kibanaRegionMapLayerWizardConfig); +registerLayerWizard(kibanaBasemapLayerWizardConfig); +registerLayerWizard(tmsLayerWizardConfig); +registerLayerWizard(wmsLayerWizardConfig); diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js b/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js deleted file mode 100644 index 6a518609dd77f..0000000000000 --- a/x-pack/legacy/plugins/maps/public/layers/sources/all_sources.js +++ /dev/null @@ -1,29 +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 { EMSFileSource } from './ems_file_source'; -import { GeojsonFileSource } from './client_file_source'; -import { KibanaRegionmapSource } from './kibana_regionmap_source'; -import { XYZTMSSource } from './xyz_tms_source'; -import { EMSTMSSource } from './ems_tms_source'; -import { WMSSource } from './wms_source'; -import { KibanaTilemapSource } from './kibana_tilemap_source'; -import { ESGeoGridSource } from './es_geo_grid_source'; -import { ESSearchSource } from './es_search_source'; -import { ESPewPewSource } from './es_pew_pew_source/es_pew_pew_source'; - -export const ALL_SOURCES = [ - GeojsonFileSource, - ESSearchSource, - ESGeoGridSource, - ESPewPewSource, - EMSFileSource, - EMSTMSSource, - KibanaRegionmapSource, - KibanaTilemapSource, - XYZTMSSource, - WMSSource, -]; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js index a38669fcd1d1a..1003f8329da22 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/geojson_file_source.js @@ -16,16 +16,11 @@ import { ESSearchSource } from '../es_search_source'; import uuid from 'uuid/v4'; import _ from 'lodash'; import { i18n } from '@kbn/i18n'; +import { registerSource } from '../source_registry'; export class GeojsonFileSource extends AbstractVectorSource { static type = GEOJSON_FILE; - static title = i18n.translate('xpack.maps.source.geojsonFileTitle', { - defaultMessage: 'Uploaded GeoJSON', - }); - static description = i18n.translate('xpack.maps.source.geojsonFileDescription', { - defaultMessage: 'Upload and index GeoJSON data in Elasticsearch', - }); - static icon = 'importAction'; + static isIndexingSource = true; static createDescriptor(geoJson, name) { @@ -59,62 +54,93 @@ export class GeojsonFileSource extends AbstractVectorSource { }; } - static viewIndexedData = ( - addAndViewSource, - inspectorAdapters, - importSuccessHandler, - importErrorHandler - ) => { - return (indexResponses = {}) => { - const { indexDataResp, indexPatternResp } = indexResponses; - - const indexCreationFailed = !(indexDataResp && indexDataResp.success); - const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount; - const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success); - - if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) { - importErrorHandler(indexResponses); - return; - } - const { fields, id } = indexPatternResp; - const geoFieldArr = fields.filter(field => - Object.values(ES_GEO_FIELD_TYPE).includes(field.type) - ); - const geoField = _.get(geoFieldArr, '[0].name'); - const indexPatternId = id; - if (!indexPatternId || !geoField) { - addAndViewSource(null); - } else { - // Only turn on bounds filter for large doc counts - const filterByMapBounds = indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW; - const source = new ESSearchSource( - { - id: uuid(), - indexPatternId, - geoField, - filterByMapBounds, - }, - inspectorAdapters - ); - addAndViewSource(source); - importSuccessHandler(indexResponses); - } + async getGeoJsonWithMeta() { + return { + data: this._descriptor.__featureCollection, + meta: {}, }; + } + + async getDisplayName() { + return this._descriptor.name; + } + + canFormatFeatureProperties() { + return true; + } + + shouldBeIndexed() { + return GeojsonFileSource.isIndexingSource; + } +} + +const viewIndexedData = ( + addAndViewSource, + inspectorAdapters, + importSuccessHandler, + importErrorHandler +) => { + return (indexResponses = {}) => { + const { indexDataResp, indexPatternResp } = indexResponses; + + const indexCreationFailed = !(indexDataResp && indexDataResp.success); + const allDocsFailed = indexDataResp.failures.length === indexDataResp.docCount; + const indexPatternCreationFailed = !(indexPatternResp && indexPatternResp.success); + + if (indexCreationFailed || allDocsFailed || indexPatternCreationFailed) { + importErrorHandler(indexResponses); + return; + } + const { fields, id } = indexPatternResp; + const geoFieldArr = fields.filter(field => + Object.values(ES_GEO_FIELD_TYPE).includes(field.type) + ); + const geoField = _.get(geoFieldArr, '[0].name'); + const indexPatternId = id; + if (!indexPatternId || !geoField) { + addAndViewSource(null); + } else { + // Only turn on bounds filter for large doc counts + const filterByMapBounds = indexDataResp.docCount > DEFAULT_MAX_RESULT_WINDOW; + const source = new ESSearchSource( + { + id: uuid(), + indexPatternId, + geoField, + filterByMapBounds, + }, + inspectorAdapters + ); + addAndViewSource(source); + importSuccessHandler(indexResponses); + } }; +}; - static previewGeojsonFile = (onPreviewSource, inspectorAdapters) => { - return (geojsonFile, name) => { - if (!geojsonFile) { - onPreviewSource(null); - return; - } - const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name); - const source = new GeojsonFileSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; +const previewGeojsonFile = (onPreviewSource, inspectorAdapters) => { + return (geojsonFile, name) => { + if (!geojsonFile) { + onPreviewSource(null); + return; + } + const sourceDescriptor = GeojsonFileSource.createDescriptor(geojsonFile, name); + const source = new GeojsonFileSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); }; +}; + +registerSource({ + ConstructorFunction: GeojsonFileSource, + type: GEOJSON_FILE, +}); - static renderEditor({ +export const uploadLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.geojsonFileDescription', { + defaultMessage: 'Index GeoJSON data in Elasticsearch', + }), + icon: 'importAction', + isIndexingSource: true, + renderWizard: ({ onPreviewSource, inspectorAdapters, addAndViewSource, @@ -123,15 +149,12 @@ export class GeojsonFileSource extends AbstractVectorSource { onIndexReady, importSuccessHandler, importErrorHandler, - }) { + }) => { return ( ); - } - - async getGeoJsonWithMeta() { - return { - data: this._descriptor.__featureCollection, - meta: {}, - }; - } - - async getDisplayName() { - return this._descriptor.name; - } - - canFormatFeatureProperties() { - return true; - } - - shouldBeIndexed() { - return GeojsonFileSource.isIndexingSource; - } -} + }, + title: i18n.translate('xpack.maps.source.geojsonFileTitle', { + defaultMessage: 'Upload GeoJSON', + }), +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/index.js index cf0d15dcb747a..a6a31def4b231 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/client_file_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { GeojsonFileSource } from './geojson_file_source'; +export { GeojsonFileSource, uploadLayerWizardConfig } from './geojson_file_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js index 524f030862768..d3ccc0cb55821 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/ems_file_source.js @@ -14,16 +14,14 @@ import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { UpdateSourceEditor } from './update_source_editor'; import { EMSFileField } from '../../fields/ems_file_field'; +import { registerSource } from '../source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', { + defaultMessage: 'EMS Boundaries', +}); export class EMSFileSource extends AbstractVectorSource { static type = EMS_FILE; - static title = i18n.translate('xpack.maps.source.emsFileTitle', { - defaultMessage: 'EMS Boundaries', - }); - static description = i18n.translate('xpack.maps.source.emsFileDescription', { - defaultMessage: 'Administrative boundaries from Elastic Maps Service', - }); - static icon = 'emsApp'; static createDescriptor({ id, tooltipProperties = [] }) { return { @@ -33,15 +31,6 @@ export class EMSFileSource extends AbstractVectorSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig); - const source = new EMSFileSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - } - constructor(descriptor, inspectorAdapters) { super(EMSFileSource.createDescriptor(descriptor), inspectorAdapters); this._tooltipFields = this._descriptor.tooltipProperties.map(propertyKey => @@ -118,7 +107,7 @@ export class EMSFileSource extends AbstractVectorSource { return [ { label: getDataSourceLabel(), - value: EMSFileSource.title, + value: sourceTitle, }, { label: i18n.translate('xpack.maps.source.emsFile.layerLabel', { @@ -167,3 +156,24 @@ export class EMSFileSource extends AbstractVectorSource { return [VECTOR_SHAPE_TYPES.POLYGON]; } } + +registerSource({ + ConstructorFunction: EMSFileSource, + type: EMS_FILE, +}); + +export const emsBoundariesLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.emsFileDescription', { + defaultMessage: 'Administrative boundaries from Elastic Maps Service', + }), + icon: 'emsApp', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + const sourceDescriptor = EMSFileSource.createDescriptor(sourceConfig); + const source = new EMSFileSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/index.js index 9d0e503eb08ba..28fbc04a1a032 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/ems_file_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EMSFileSource } from './ems_file_source'; +export { EMSFileSource, emsBoundariesLayerWizardConfig } from './ems_file_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js index 5a2124622694c..1da3680dfdc86 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/ems_tms_source.js @@ -16,16 +16,14 @@ import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import { EMS_TMS } from '../../../../common/constants'; import { getInjectedVarFunc, getUiSettings } from '../../../kibana_services'; +import { registerSource } from '../source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.emsTileTitle', { + defaultMessage: 'EMS Basemaps', +}); export class EMSTMSSource extends AbstractTMSSource { static type = EMS_TMS; - static title = i18n.translate('xpack.maps.source.emsTileTitle', { - defaultMessage: 'EMS Basemaps', - }); - static description = i18n.translate('xpack.maps.source.emsTileDescription', { - defaultMessage: 'Tile map service from Elastic Maps Service', - }); - static icon = 'emsApp'; static createDescriptor(sourceConfig) { return { @@ -35,16 +33,6 @@ export class EMSTMSSource extends AbstractTMSSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - const descriptor = EMSTMSSource.createDescriptor(sourceConfig); - const source = new EMSTMSSource(descriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - } - constructor(descriptor, inspectorAdapters) { super( { @@ -69,7 +57,7 @@ export class EMSTMSSource extends AbstractTMSSource { return [ { label: getDataSourceLabel(), - value: EMSTMSSource.title, + value: sourceTitle, }, { label: i18n.translate('xpack.maps.source.emsTile.serviceId', { @@ -157,3 +145,25 @@ export class EMSTMSSource extends AbstractTMSSource { return isDarkMode ? emsTileLayerId.dark : emsTileLayerId.bright; } } + +registerSource({ + ConstructorFunction: EMSTMSSource, + type: EMS_TMS, +}); + +export const emsBaseMapLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.emsTileDescription', { + defaultMessage: 'Tile map service from Elastic Maps Service', + }), + icon: 'emsApp', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + const descriptor = EMSTMSSource.createDescriptor(sourceConfig); + const source = new EMSTMSSource(descriptor, inspectorAdapters); + onPreviewSource(source); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/index.js index 81306578db4ae..60a4c9b1de891 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/ems_tms_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { EMSTMSSource } from './ems_tms_source'; +export { EMSTMSSource, emsBaseMapLayerWizardConfig } from './ems_tms_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/create_source_editor.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/create_source_editor.js index 148683269ef78..4aec390bec745 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/create_source_editor.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/create_source_editor.js @@ -14,32 +14,12 @@ import { getIndexPatternService, getIndexPatternSelectComponent } from '../../.. import { NoIndexPatternCallout } from '../../../components/no_index_pattern_callout'; import { i18n } from '@kbn/i18n'; -import { EuiFormRow, EuiComboBox, EuiSpacer } from '@elastic/eui'; +import { EuiFormRow, EuiSpacer } from '@elastic/eui'; import { AGGREGATABLE_GEO_FIELD_TYPES, getAggregatableGeoFields, } from '../../../index_pattern_util'; - -const requestTypeOptions = [ - { - label: i18n.translate('xpack.maps.source.esGeoGrid.gridRectangleDropdownOption', { - defaultMessage: 'grid rectangles', - }), - value: RENDER_AS.GRID, - }, - { - label: i18n.translate('xpack.maps.source.esGeoGrid.heatmapDropdownOption', { - defaultMessage: 'heat map', - }), - value: RENDER_AS.HEATMAP, - }, - { - label: i18n.translate('xpack.maps.source.esGeoGrid.pointsDropdownOption', { - defaultMessage: 'clusters', - }), - value: RENDER_AS.POINT, - }, -]; +import { RenderAsSelect } from './render_as_select'; export class CreateSourceEditor extends Component { static propTypes = { @@ -50,7 +30,7 @@ export class CreateSourceEditor extends Component { isLoadingIndexPattern: false, indexPatternId: '', geoField: '', - requestType: requestTypeOptions[0], + requestType: this.props.requestType, noGeoIndexPatternsExist: false, }; @@ -126,10 +106,10 @@ export class CreateSourceEditor extends Component { ); }; - _onRequestTypeSelect = selectedOptions => { + _onRequestTypeSelect = newValue => { this.setState( { - requestType: selectedOptions[0], + requestType: newValue, }, this.previewLayer ); @@ -139,9 +119,7 @@ export class CreateSourceEditor extends Component { const { indexPatternId, geoField, requestType } = this.state; const sourceConfig = - indexPatternId && geoField - ? { indexPatternId, geoField, requestType: requestType.value } - : null; + indexPatternId && geoField ? { indexPatternId, geoField, requestType } : null; this.props.onSourceConfigChange(sourceConfig); }; @@ -176,28 +154,13 @@ export class CreateSourceEditor extends Component { ); } - _renderLayerSelect() { - if (!this.state.indexPattern) { + _renderRenderAsSelect() { + if (this.state.requestType === RENDER_AS.HEATMAP || !this.state.indexPattern) { return null; } return ( - - - + ); } @@ -243,7 +206,7 @@ export class CreateSourceEditor extends Component { {this._renderNoIndexPatternWarning()} {this._renderIndexPatternSelect()} {this._renderGeoSelect()} - {this._renderLayerSelect()} + {this._renderRenderAsSelect()} ); } diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js index 405c8a61bfca6..dec802ac3cf1a 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/es_geo_grid_source.js @@ -32,17 +32,20 @@ import { AbstractESAggSource } from '../es_agg_source'; import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; import { StaticStyleProperty } from '../../styles/vector/properties/static_style_property'; import { DataRequestAbortError } from '../../util/data_request'; +import { registerSource } from '../source_registry'; export const MAX_GEOTILE_LEVEL = 29; +const clustersTitle = i18n.translate('xpack.maps.source.esGridClustersTitle', { + defaultMessage: 'Clusters and grids', +}); + +const heatmapTitle = i18n.translate('xpack.maps.source.esGridHeatmapTitle', { + defaultMessage: 'Heat map', +}); + export class ESGeoGridSource extends AbstractESAggSource { static type = ES_GEO_GRID; - static title = i18n.translate('xpack.maps.source.esGridTitle', { - defaultMessage: 'Grid aggregation', - }); - static description = i18n.translate('xpack.maps.source.esGridDescription', { - defaultMessage: 'Geospatial data grouped in grids with metrics for each gridded cell', - }); static createDescriptor({ indexPatternId, geoField, requestType, resolution }) { return { @@ -55,21 +58,6 @@ export class ESGeoGridSource extends AbstractESAggSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig); - const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - } - renderSourceSettingsEditor({ onChange }) { return ( { + const onSourceConfigChange = sourceConfig => { + if (!sourceConfig) { + onPreviewSource(null); + return; + } + + const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig); + const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + + return ( + + ); + }, + title: clustersTitle, +}; + +export const heatmapLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.esGridHeatmapDescription', { + defaultMessage: 'Geospatial data grouped in grids to show density', + }), + icon: 'logoElasticsearch', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + if (!sourceConfig) { + onPreviewSource(null); + return; + } + + const sourceDescriptor = ESGeoGridSource.createDescriptor(sourceConfig); + const source = new ESGeoGridSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + + return ( + + ); + }, + title: heatmapTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/index.js index 58d74c04c5552..c2fa2356b1a3e 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/index.js @@ -4,4 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ESGeoGridSource } from './es_geo_grid_source'; +export { + ESGeoGridSource, + clustersLayerWizardConfig, + heatmapLayerWizardConfig, +} from './es_geo_grid_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/render_as_select.tsx b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/render_as_select.tsx new file mode 100644 index 0000000000000..c82781ede186f --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_geo_grid_source/render_as_select.tsx @@ -0,0 +1,59 @@ +/* + * 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 { EuiFormRow, EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { RENDER_AS } from '../../../../common/constants'; + +const options = [ + { + label: i18n.translate('xpack.maps.source.esGeoGrid.pointsDropdownOption', { + defaultMessage: 'clusters', + }), + value: RENDER_AS.POINT, + }, + { + label: i18n.translate('xpack.maps.source.esGeoGrid.gridRectangleDropdownOption', { + defaultMessage: 'grids', + }), + value: RENDER_AS.GRID, + }, +]; + +export function RenderAsSelect(props: { + renderAs: RENDER_AS; + onChange: (newValue: RENDER_AS) => void; +}) { + function onChange(selectedOptions: Array>) { + if (!selectedOptions || !selectedOptions.length) { + return; + } + props.onChange(selectedOptions[0].value as RENDER_AS); + } + + const selectedOptions = []; + const selectedOption = options.find(option => option.value === props.renderAs); + if (selectedOption) { + selectedOptions.push(selectedOption); + } + + return ( + + + + ); +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js index 5f6cc0a46dfb2..da2b663746b9d 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_pew_pew_source/es_pew_pew_source.js @@ -26,17 +26,16 @@ import { AbstractESAggSource } from '../es_agg_source'; import { DynamicStyleProperty } from '../../styles/vector/properties/dynamic_style_property'; import { COLOR_GRADIENTS } from '../../styles/color_utils'; import { indexPatterns } from '../../../../../../../../src/plugins/data/public'; +import { registerSource } from '../source_registry'; const MAX_GEOTILE_LEVEL = 29; +const sourceTitle = i18n.translate('xpack.maps.source.pewPewTitle', { + defaultMessage: 'Point to point', +}); + export class ESPewPewSource extends AbstractESAggSource { static type = ES_PEW_PEW; - static title = i18n.translate('xpack.maps.source.pewPewTitle', { - defaultMessage: 'Point to point', - }); - static description = i18n.translate('xpack.maps.source.pewPewDescription', { - defaultMessage: 'Aggregated data paths between the source and destination', - }); static createDescriptor({ indexPatternId, sourceGeoField, destGeoField }) { return { @@ -48,21 +47,6 @@ export class ESPewPewSource extends AbstractESAggSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = ESPewPewSource.createDescriptor(sourceConfig); - const source = new ESPewPewSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - } - renderSourceSettingsEditor({ onChange }) { return ( { + const onSourceConfigChange = sourceConfig => { + if (!sourceConfig) { + onPreviewSource(null); + return; + } + + const sourceDescriptor = ESPewPewSource.createDescriptor(sourceConfig); + const source = new ESPewPewSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js index cd44ef49623fa..ce9932bd15cea 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/es_search_source.js @@ -32,6 +32,11 @@ import { BlendedVectorLayer } from '../../blended_vector_layer'; import { DEFAULT_FILTER_BY_MAP_BOUNDS } from './constants'; import { ESDocField } from '../../fields/es_doc_field'; import { getField, addFieldToDSL } from '../../util/es_agg_utils'; +import { registerSource } from '../source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.esSearchTitle', { + defaultMessage: 'Documents', +}); function getDocValueAndSourceFields(indexPattern, fieldNames) { const docValueFields = []; @@ -65,31 +70,6 @@ function getDocValueAndSourceFields(indexPattern, fieldNames) { export class ESSearchSource extends AbstractESSource { static type = ES_SEARCH; - static title = i18n.translate('xpack.maps.source.esSearchTitle', { - defaultMessage: 'Documents', - }); - static description = i18n.translate('xpack.maps.source.esSearchDescription', { - defaultMessage: 'Vector data from a Kibana index pattern', - }); - - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const source = new ESSearchSource( - { - id: uuid(), - ...sourceConfig, - }, - inspectorAdapters - ); - onPreviewSource(source); - }; - return ; - } constructor(descriptor, inspectorAdapters) { super( @@ -206,7 +186,7 @@ export class ESSearchSource extends AbstractESSource { return [ { label: getDataSourceLabel(), - value: ESSearchSource.title, + value: sourceTitle, }, { label: i18n.translate('xpack.maps.source.esSearch.indexPatternLabel', { @@ -587,3 +567,34 @@ export class ESSearchSource extends AbstractESSource { }; } } + +registerSource({ + ConstructorFunction: ESSearchSource, + type: ES_SEARCH, +}); + +export const esDocumentsLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.esSearchDescription', { + defaultMessage: 'Vector data from a Kibana index pattern', + }), + icon: 'logoElasticsearch', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + if (!sourceConfig) { + onPreviewSource(null); + return; + } + + const source = new ESSearchSource( + { + id: uuid(), + ...sourceConfig, + }, + inspectorAdapters + ); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/index.js index 5fea38ee274d9..2c401ac92567e 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_search_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { ESSearchSource } from './es_search_source'; +export { ESSearchSource, esDocumentsLayerWizardConfig } from './es_search_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js index 9dc3067a70436..bf04a73cfba77 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/es_source.js @@ -23,8 +23,6 @@ import { DataRequestAbortError } from '../util/data_request'; import { expandToTileBoundaries } from './es_geo_grid_source/geo_tile_utils'; export class AbstractESSource extends AbstractVectorSource { - static icon = 'logoElasticsearch'; - constructor(descriptor, inspectorAdapters) { super( { diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js index d54b135239a63..00c3bfc5f17c6 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { KibanaRegionmapSource } from './kibana_regionmap_source'; +export { KibanaRegionmapSource, kibanaRegionMapLayerWizardConfig } from './kibana_regionmap_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js index 276a3377aaae2..7f4bcfa41f7c4 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_regionmap_source/kibana_regionmap_source.js @@ -10,18 +10,16 @@ import { CreateSourceEditor } from './create_source_editor'; import { getKibanaRegionList } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; -import { FIELD_ORIGIN } from '../../../../common/constants'; +import { FIELD_ORIGIN, REGIONMAP_FILE } from '../../../../common/constants'; import { KibanaRegionField } from '../../fields/kibana_region_field'; +import { registerSource } from '../source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.kbnRegionMapTitle', { + defaultMessage: 'Configured GeoJSON', +}); export class KibanaRegionmapSource extends AbstractVectorSource { - static type = 'REGIONMAP_FILE'; - static title = i18n.translate('xpack.maps.source.kbnRegionMapTitle', { - defaultMessage: 'Configured GeoJSON', - }); - static description = i18n.translate('xpack.maps.source.kbnRegionMapDescription', { - defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml', - }); - static icon = 'logoKibana'; + static type = REGIONMAP_FILE; static createDescriptor({ name }) { return { @@ -30,16 +28,6 @@ export class KibanaRegionmapSource extends AbstractVectorSource { }; } - static renderEditor = ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = sourceConfig => { - const sourceDescriptor = KibanaRegionmapSource.createDescriptor(sourceConfig); - const source = new KibanaRegionmapSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - - return ; - }; - createField({ fieldName }) { return new KibanaRegionField({ fieldName, @@ -52,7 +40,7 @@ export class KibanaRegionmapSource extends AbstractVectorSource { return [ { label: getDataSourceLabel(), - value: KibanaRegionmapSource.title, + value: sourceTitle, }, { label: i18n.translate('xpack.maps.source.kbnRegionMap.vectorLayerLabel', { @@ -108,3 +96,25 @@ export class KibanaRegionmapSource extends AbstractVectorSource { return true; } } + +registerSource({ + ConstructorFunction: KibanaRegionmapSource, + type: REGIONMAP_FILE, +}); + +export const kibanaRegionMapLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.kbnRegionMapDescription', { + defaultMessage: 'Vector data from hosted GeoJSON configured in kibana.yml', + }), + icon: 'logoKibana', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + const sourceDescriptor = KibanaRegionmapSource.createDescriptor(sourceConfig); + const source = new KibanaRegionmapSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js index 3226fb89b700b..9fd7f088032ca 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { KibanaTilemapSource } from './kibana_tilemap_source'; +export { KibanaTilemapSource, kibanaBasemapLayerWizardConfig } from './kibana_tilemap_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js index 21ab2ba42c7bb..b21bb6bdbbad4 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/kibana_tilemap_source/kibana_tilemap_source.js @@ -11,17 +11,15 @@ import { getKibanaTileMap } from '../../../meta'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel } from '../../../../common/i18n_getters'; import _ from 'lodash'; +import { KIBANA_TILEMAP } from '../../../../common/constants'; +import { registerSource } from '../source_registry'; -export class KibanaTilemapSource extends AbstractTMSSource { - static type = 'KIBANA_TILEMAP'; - static title = i18n.translate('xpack.maps.source.kbnTMSTitle', { - defaultMessage: 'Configured Tile Map Service', - }); - static description = i18n.translate('xpack.maps.source.kbnTMSDescription', { - defaultMessage: 'Tile map service configured in kibana.yml', - }); +const sourceTitle = i18n.translate('xpack.maps.source.kbnTMSTitle', { + defaultMessage: 'Configured Tile Map Service', +}); - static icon = 'logoKibana'; +export class KibanaTilemapSource extends AbstractTMSSource { + static type = KIBANA_TILEMAP; static createDescriptor() { return { @@ -29,20 +27,11 @@ export class KibanaTilemapSource extends AbstractTMSSource { }; } - static renderEditor = ({ onPreviewSource, inspectorAdapters }) => { - const onSourceConfigChange = () => { - const sourceDescriptor = KibanaTilemapSource.createDescriptor(); - const source = new KibanaTilemapSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - }; - async getImmutableProperties() { return [ { label: getDataSourceLabel(), - value: KibanaTilemapSource.title, + value: sourceTitle, }, { label: i18n.translate('xpack.maps.source.kbnTMS.urlLabel', { @@ -94,3 +83,24 @@ export class KibanaTilemapSource extends AbstractTMSSource { } } } + +registerSource({ + ConstructorFunction: KibanaTilemapSource, + type: KIBANA_TILEMAP, +}); + +export const kibanaBasemapLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.kbnTMSDescription', { + defaultMessage: 'Tile map service configured in kibana.yml', + }), + icon: 'logoKibana', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = () => { + const sourceDescriptor = KibanaTilemapSource.createDescriptor(); + const source = new KibanaTilemapSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/source_registry.ts b/x-pack/legacy/plugins/maps/public/layers/sources/source_registry.ts new file mode 100644 index 0000000000000..518cab68b601b --- /dev/null +++ b/x-pack/legacy/plugins/maps/public/layers/sources/source_registry.ts @@ -0,0 +1,35 @@ +/* + * 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 @typescript-eslint/consistent-type-definitions */ + +import { AbstractSourceDescriptor } from '../../../common/descriptor_types'; +import { ISource } from './source'; + +type SourceRegistryEntry = { + ConstructorFunction: new ( + sourceDescriptor: AbstractSourceDescriptor, + inspectorAdapters: unknown + ) => ISource; + type: string; +}; + +const registry: SourceRegistryEntry[] = []; + +export function registerSource(entry: SourceRegistryEntry) { + const sourceTypeExists = registry.some(({ type }: SourceRegistryEntry) => { + return entry.type === type; + }); + if (sourceTypeExists) { + throw new Error( + `Unable to register source type ${entry.type}. ${entry.type} has already been registered` + ); + } + registry.push(entry); +} + +export function getSourceByType(sourceType: string): SourceRegistryEntry | undefined { + return registry.find((source: SourceRegistryEntry) => source.type === sourceType); +} diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/index.js b/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/index.js index 22bc50e601f56..daae552a6f772 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/index.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { WMSSource } from './wms_source'; +export { WMSSource, wmsLayerWizardConfig } from './wms_source'; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/wms_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/wms_source.js index 61955df94e451..749560a2bb4b1 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/wms_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/wms_source/wms_source.js @@ -12,16 +12,15 @@ import { WMSCreateSourceEditor } from './wms_create_source_editor'; import { i18n } from '@kbn/i18n'; import { getDataSourceLabel, getUrlLabel } from '../../../../common/i18n_getters'; import { WmsClient } from './wms_client'; +import { WMS } from '../../../../common/constants'; +import { registerSource } from '../source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.wmsTitle', { + defaultMessage: 'Web Map Service', +}); export class WMSSource extends AbstractTMSSource { - static type = 'WMS'; - static title = i18n.translate('xpack.maps.source.wmsTitle', { - defaultMessage: 'Web Map Service', - }); - static description = i18n.translate('xpack.maps.source.wmsDescription', { - defaultMessage: 'Maps from OGC Standard WMS', - }); - static icon = 'grid'; + static type = WMS; static createDescriptor({ serviceUrl, layers, styles, attributionText, attributionUrl }) { return { @@ -34,23 +33,9 @@ export class WMSSource extends AbstractTMSSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - if (!sourceConfig) { - onPreviewSource(null); - return; - } - - const sourceDescriptor = WMSSource.createDescriptor(sourceConfig); - const source = new WMSSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - } - async getImmutableProperties() { return [ - { label: getDataSourceLabel(), value: WMSSource.title }, + { label: getDataSourceLabel(), value: sourceTitle }, { label: getUrlLabel(), value: this._descriptor.serviceUrl }, { label: i18n.translate('xpack.maps.source.wms.layersLabel', { @@ -104,3 +89,29 @@ export class WMSSource extends AbstractTMSSource { return client.getUrlTemplate(this._descriptor.layers, this._descriptor.styles || ''); } } + +registerSource({ + ConstructorFunction: WMSSource, + type: WMS, +}); + +export const wmsLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.wmsDescription', { + defaultMessage: 'Maps from OGC Standard WMS', + }), + icon: 'grid', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + if (!sourceConfig) { + onPreviewSource(null); + return; + } + + const sourceDescriptor = WMSSource.createDescriptor(sourceConfig); + const source = new WMSSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js index 354883372e244..d53fbffd21512 100644 --- a/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js +++ b/x-pack/legacy/plugins/maps/public/layers/sources/xyz_tms_source.js @@ -13,16 +13,14 @@ import { i18n } from '@kbn/i18n'; import { getDataSourceLabel, getUrlLabel } from '../../../common/i18n_getters'; import _ from 'lodash'; import { EMS_XYZ } from '../../../common/constants'; +import { registerSource } from './source_registry'; + +const sourceTitle = i18n.translate('xpack.maps.source.ems_xyzTitle', { + defaultMessage: 'Tile Map Service', +}); export class XYZTMSSource extends AbstractTMSSource { static type = EMS_XYZ; - static title = i18n.translate('xpack.maps.source.ems_xyzTitle', { - defaultMessage: 'Tile Map Service', - }); - static description = i18n.translate('xpack.maps.source.ems_xyzDescription', { - defaultMessage: 'Tile map service configured in interface', - }); - static icon = 'grid'; static createDescriptor({ urlTemplate, attributionText, attributionUrl }) { return { @@ -33,18 +31,9 @@ export class XYZTMSSource extends AbstractTMSSource { }; } - static renderEditor({ onPreviewSource, inspectorAdapters }) { - const onSourceConfigChange = sourceConfig => { - const sourceDescriptor = XYZTMSSource.createDescriptor(sourceConfig); - const source = new XYZTMSSource(sourceDescriptor, inspectorAdapters); - onPreviewSource(source); - }; - return ; - } - async getImmutableProperties() { return [ - { label: getDataSourceLabel(), value: XYZTMSSource.title }, + { label: getDataSourceLabel(), value: sourceTitle }, { label: getUrlLabel(), value: this._descriptor.urlTemplate }, ]; } @@ -175,3 +164,24 @@ class XYZTMSEditor extends React.Component { ); } } + +registerSource({ + ConstructorFunction: XYZTMSSource, + type: EMS_XYZ, +}); + +export const tmsLayerWizardConfig = { + description: i18n.translate('xpack.maps.source.ems_xyzDescription', { + defaultMessage: 'Tile map service configured in interface', + }), + icon: 'grid', + renderWizard: ({ onPreviewSource, inspectorAdapters }) => { + const onSourceConfigChange = sourceConfig => { + const sourceDescriptor = XYZTMSSource.createDescriptor(sourceConfig); + const source = new XYZTMSSource(sourceDescriptor, inspectorAdapters); + onPreviewSource(source); + }; + return ; + }, + title: sourceTitle, +}; diff --git a/x-pack/legacy/plugins/maps/public/plugin.ts b/x-pack/legacy/plugins/maps/public/plugin.ts index 53c951ac787e1..c08ed6fc6da61 100644 --- a/x-pack/legacy/plugins/maps/public/plugin.ts +++ b/x-pack/legacy/plugins/maps/public/plugin.ts @@ -4,6 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import './layers/layer_wizard_registry'; +import './layers/sources/source_registry'; +import './layers/load_layer_wizards'; + import { Plugin, CoreStart, CoreSetup } from 'src/core/public'; // @ts-ignore import { wrapInI18nContext } from 'ui/i18n'; diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js index 61eea2d172ae4..397478cfd1d1b 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js +++ b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.js @@ -11,7 +11,6 @@ import { VectorTileLayer } from '../layers/vector_tile_layer'; import { VectorLayer } from '../layers/vector_layer'; import { HeatmapLayer } from '../layers/heatmap_layer'; import { BlendedVectorLayer } from '../layers/blended_vector_layer'; -import { ALL_SOURCES } from '../layers/sources/all_sources'; import { getTimeFilter } from '../kibana_services'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { getInspectorAdapters } from '../../../../../plugins/maps/public/reducers/non_serializable_instances'; @@ -21,6 +20,7 @@ import { // eslint-disable-next-line @kbn/eslint/no-restricted-paths } from '../../../../../plugins/maps/public/reducers/util'; import { InnerJoin } from '../layers/joins/inner_join'; +import { getSourceByType } from '../layers/sources/source_registry'; function createLayerInstance(layerDescriptor, inspectorAdapters) { const source = createSourceInstance(layerDescriptor.sourceDescriptor, inspectorAdapters); @@ -49,13 +49,11 @@ function createLayerInstance(layerDescriptor, inspectorAdapters) { } function createSourceInstance(sourceDescriptor, inspectorAdapters) { - const Source = ALL_SOURCES.find(Source => { - return Source.type === sourceDescriptor.type; - }); - if (!Source) { + const source = getSourceByType(sourceDescriptor.type); + if (!source) { throw new Error(`Unrecognized sourceType ${sourceDescriptor.type}`); } - return new Source(sourceDescriptor, inspectorAdapters); + return new source.ConstructorFunction(sourceDescriptor, inspectorAdapters); } export const getOpenTooltips = ({ map }) => { diff --git a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js index e7f071d5729c6..1a5ab633a569f 100644 --- a/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js +++ b/x-pack/legacy/plugins/maps/public/selectors/map_selectors.test.js @@ -8,7 +8,6 @@ jest.mock('../layers/vector_layer', () => {}); jest.mock('../layers/blended_vector_layer', () => {}); jest.mock('../layers/heatmap_layer', () => {}); jest.mock('../layers/vector_tile_layer', () => {}); -jest.mock('../layers/sources/all_sources', () => {}); jest.mock('../layers/joins/inner_join', () => {}); jest.mock('../../../../../plugins/maps/public/reducers/non_serializable_instances', () => ({ getInspectorAdapters: () => { diff --git a/x-pack/plugins/maps/common/constants.ts b/x-pack/plugins/maps/common/constants.ts index 30a3350ad754e..bd4406ef5ce63 100644 --- a/x-pack/plugins/maps/common/constants.ts +++ b/x-pack/plugins/maps/common/constants.ts @@ -62,6 +62,9 @@ export const ES_GEO_GRID = 'ES_GEO_GRID'; export const ES_SEARCH = 'ES_SEARCH'; export const ES_PEW_PEW = 'ES_PEW_PEW'; export const EMS_XYZ = 'EMS_XYZ'; // identifies a custom TMS source. Name is a little unfortunate. +export const WMS = 'WMS'; +export const KIBANA_TILEMAP = 'KIBANA_TILEMAP'; +export const REGIONMAP_FILE = 'REGIONMAP_FILE'; export enum FIELD_ORIGIN { SOURCE = 'source', diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9e733fd0e6fc6..96e0bdf8f4804 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -7137,12 +7137,10 @@ "xpack.maps.source.esGeoGrid.geofieldLabel": "地理空間フィールド", "xpack.maps.source.esGeoGrid.geofieldPlaceholder": "ジオフィールドを選択", "xpack.maps.source.esGeoGrid.gridRectangleDropdownOption": "グリッド四角", - "xpack.maps.source.esGeoGrid.heatmapDropdownOption": "ヒートマップ", "xpack.maps.source.esGeoGrid.indexPatternLabel": "インデックスパターン", "xpack.maps.source.esGeoGrid.indexPatternPlaceholder": "インデックスパターンを選択", "xpack.maps.source.esGeoGrid.pointsDropdownOption": "点", "xpack.maps.source.esGeoGrid.showAsLabel": "表示形式", - "xpack.maps.source.esGeoGrid.showAsPlaceholder": "1 つのオプションを選択", "xpack.maps.source.esGrid.coarseDropdownOption": "粗い", "xpack.maps.source.esGrid.fineDropdownOption": "細かい", "xpack.maps.source.esGrid.finestDropdownOption": "最も細かい", @@ -7151,9 +7149,6 @@ "xpack.maps.source.esGrid.metricsLabel": "メトリック", "xpack.maps.source.esGrid.noIndexPatternErrorMessage": "インデックスパターン {id} が見つかりません", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "グリッド解像度パラメーターが認識されません: {resolution}", - "xpack.maps.source.esGrid.showasFieldLabel": "表示形式", - "xpack.maps.source.esGridDescription": "それぞれのグリッド付きセルのメトリックでグリッドにグループ分けされた地理空間データです。", - "xpack.maps.source.esGridTitle": "グリッド集約", "xpack.maps.source.esSearch.convertToGeoJsonErrorMsg": "検索への応答を geoJson 機能コレクションに変換できません。エラー: {errorMsg}", "xpack.maps.source.esSearch.extentFilterLabel": "マップの表示範囲でデータを動的にフィルタリング", "xpack.maps.source.esSearch.geofieldLabel": "地理空間フィールド", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1555b3adaaa22..fe72ff54ef5ea 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7137,12 +7137,10 @@ "xpack.maps.source.esGeoGrid.geofieldLabel": "地理空间字段", "xpack.maps.source.esGeoGrid.geofieldPlaceholder": "选择地理字段", "xpack.maps.source.esGeoGrid.gridRectangleDropdownOption": "网格矩形", - "xpack.maps.source.esGeoGrid.heatmapDropdownOption": "热图", "xpack.maps.source.esGeoGrid.indexPatternLabel": "索引模式", "xpack.maps.source.esGeoGrid.indexPatternPlaceholder": "选择索引模式", "xpack.maps.source.esGeoGrid.pointsDropdownOption": "磅", "xpack.maps.source.esGeoGrid.showAsLabel": "显示为", - "xpack.maps.source.esGeoGrid.showAsPlaceholder": "选择单个选项", "xpack.maps.source.esGrid.coarseDropdownOption": "粗糙", "xpack.maps.source.esGrid.fineDropdownOption": "精致", "xpack.maps.source.esGrid.finestDropdownOption": "最精致化", @@ -7151,9 +7149,6 @@ "xpack.maps.source.esGrid.metricsLabel": "指标", "xpack.maps.source.esGrid.noIndexPatternErrorMessage": "找不到索引模式 {id}", "xpack.maps.source.esGrid.resolutionParamErrorMessage": "无法识别网格分辨率参数:{resolution}", - "xpack.maps.source.esGrid.showasFieldLabel": "显示为", - "xpack.maps.source.esGridDescription": "地理空间数据在网格中进行分组,每个网格单元格都具有指标", - "xpack.maps.source.esGridTitle": "网格聚合", "xpack.maps.source.esSearch.convertToGeoJsonErrorMsg": "无法将搜索响应转换成 geoJson 功能集合,错误:{errorMsg}", "xpack.maps.source.esSearch.extentFilterLabel": "在可见地图区域中动态筛留数据", "xpack.maps.source.esSearch.geofieldLabel": "地理空间字段", diff --git a/x-pack/test/functional/page_objects/gis_page.js b/x-pack/test/functional/page_objects/gis_page.js index 537d9a29f2015..c87fd1417cf07 100644 --- a/x-pack/test/functional/page_objects/gis_page.js +++ b/x-pack/test/functional/page_objects/gis_page.js @@ -511,7 +511,7 @@ export function GisPageProvider({ getService, getPageObjects }) { async selectGeoJsonUploadSource() { log.debug(`Select upload geojson source`); - await testSubjects.click('uploadedGeoJson'); + await testSubjects.click('uploadGeoJson'); } async uploadJsonFileForIndexing(path) {