Skip to content

Commit

Permalink
[Build] Update default maps client
Browse files Browse the repository at this point in the history
Update to not use EMS so it works out of the box.
Related to: opensearch-project#221

Fails linter and should problem write more unit tests but working with smoke tests.

Signed-off-by: Kawika Avilla <[email protected]>
  • Loading branch information
kavilla committed Apr 29, 2021
1 parent 126c2b8 commit 19e3340
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ opensearch_dashboards_vars=(
logging.silent
logging.useUTC
logging.verbose
map.includeElasticMapsService
map.proxyElasticMapsServiceInMaps
map.includeOpenSearchMapsService
map.proxyOpenSearchMapsServiceInMaps
map.regionmap
map.tilemap.options.attribution
map.tilemap.options.maxZoom
Expand Down
70 changes: 69 additions & 1 deletion src/legacy/server/config/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,75 @@ export default () =>
path: HANDLED_IN_NEW_PLATFORM,
stats: HANDLED_IN_NEW_PLATFORM,
status: HANDLED_IN_NEW_PLATFORM,
map: HANDLED_IN_NEW_PLATFORM,

map: Joi.object({
includeOpenSearchMapsService: Joi.boolean().default(true),
proxyOpenSearchMapsServiceInMaps: Joi.boolean().default(false),
tilemap: Joi.object({
url: Joi.string(),
options: Joi.object({
attribution: Joi.string(),
minZoom: Joi.number().min(0, 'Must be 0 or higher').default(0),
maxZoom: Joi.number().default(10),
tileSize: Joi.number(),
subdomains: Joi.array().items(Joi.string()).single(),
errorTileUrl: Joi.string().uri(),
tms: Joi.boolean(),
reuseTiles: Joi.boolean(),
bounds: Joi.array().items(Joi.array().items(Joi.number()).min(2).required()).min(2),
default: Joi.boolean(),
}).default({
default: true,
}),
}).default(),
regionmap: Joi.object({
includeOpenSearchMapsService: Joi.boolean().default(true),
layers: Joi.array()
.items(
Joi.object({
url: Joi.string(),
format: Joi.object({
type: Joi.string().default('geojson'),
}).default({
type: 'geojson',
}),
meta: Joi.object({
feature_collection_path: Joi.string().default('data'),
}).default({
feature_collection_path: 'data',
}),
attribution: Joi.string(),
name: Joi.string(),
fields: Joi.array().items(
Joi.object({
name: Joi.string(),
description: Joi.string(),
})
),
})
)
.default([]),
}).default(),
manifestServiceUrl: Joi.string().default('').allow(''),
opensearchManifestServiceUrl: Joi.string().default(
'https://maps.search-services.aws.a2z.com/v4/ap-southeast-1/manifest'
),
emsFileApiUrl: Joi.string().default('https://vector.maps.elastic.co'),
emsTileApiUrl: Joi.string().default('https://tiles.maps.elastic.co'),
emsLandingPageUrl: Joi.string().default('https://maps.elastic.co/v7.9'),
emsFontLibraryUrl: Joi.string().default(
'https://tiles.maps.elastic.co/fonts/{fontstack}/{range}.pbf'
),
emsTileLayerId: Joi.object({
bright: Joi.string().default('road_map'),
desaturated: Joi.string().default('road_map_desaturated'),
dark: Joi.string().default('dark_map'),
}).default({
bright: 'road_map',
desaturated: 'road_map_desaturated',
dark: 'dark_map',
}),
}).default(),

i18n: Joi.object({
locale: Joi.string().default('en'),
Expand Down
3 changes: 3 additions & 0 deletions src/plugins/maps_legacy/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ export const configSchema = schema.object({
tilemap: tilemapSchema,
regionmap: regionmapSchema,
manifestServiceUrl: schema.string({ defaultValue: '' }),
opensearchManifestServiceUrl: schema.string({
defaultValue: 'https://maps.search-services.aws.a2z.com/v4/us-east-1/manifest',
}),
emsFileApiUrl: schema.string({ defaultValue: 'https://vector.maps.opensearch.org' }),
emsTileApiUrl: schema.string({ defaultValue: 'https://tiles.maps.opensearch.org' }),
emsLandingPageUrl: schema.string({ defaultValue: 'https://maps.opensearch.org/v7.10' }),
Expand Down
35 changes: 35 additions & 0 deletions src/plugins/maps_legacy/public/common/opensearch_maps_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

import { EMSClient } from '@elastic/ems-client';

export class OpenSearchMapsClient extends EMSClient {
constructor({ kbnVersion, manifestServiceUrl, language, landingPageUrl, fetchFunction }) {
super({ kbnVersion, manifestServiceUrl, language, landingPageUrl, fetchFunction });
this._queryParams = {
kbn_version: kbnVersion,
opensearch_tos_agree: true,
};
this._manifestServiceUrl = manifestServiceUrl;
}

async isEnabled() {
let result;
try {
result = await this._fetchWithTimeout(this._manifestServiceUrl);
} catch (e) {
// silently ignoring the exception and returning false.
return false;
}
if (result.ok) {
const resultJson = await result.json();
return resultJson.enabled;
}
return false;
}
}
59 changes: 57 additions & 2 deletions src/plugins/maps_legacy/public/map/map_messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,65 @@
* GitHub history for details.
*/

import React from 'react';
import React, { Fragment } from 'react';
import ReactDOM from 'react-dom';
import { FormattedMessage } from '@osd/i18n/react';
import { EuiSpacer, EuiButtonEmpty } from '@elastic/eui';
import { EuiSpacer, EuiButtonEmpty, EuiEmptyPrompt } from '@elastic/eui';
import { toMountPoint } from '../../../opensearch_dashboards_react/public';

export const createRegionBlockedWarning = (function () {
class RegionBlockedWarningOverlay extends React.Component {
constructor(props) {
super(props);
}

render() {
return (
<EuiEmptyPrompt
iconType="gisApp"
iconColor={null}
title={<h2>The default Web Map Service is currently not available in your region.</h2>}
titleSize="xs"
body={
<Fragment>
<p>
You can configure OpenSearch Dash to use a different map server for coordinate maps
by modifying the default WMS properties.
</p>
</Fragment>
}
/>
);
}
}
return () => {
let messageBlock = document.getElementById('blocker-div');
if (!messageBlock) {
messageBlock = document.createElement('div');
messageBlock.id = 'blocker-div';
messageBlock.setAttribute('class', 'visError leaflet-popup-pane');
Array.prototype.forEach.call(
document.getElementsByClassName('leaflet-container'),
(leafletDom) => {
ReactDOM.render(
new RegionBlockedWarningOverlay().render(),
leafletDom.appendChild(messageBlock)
);
}
);
}
};
})();

export const removeRegionBlockedWarning = (function () {
return () => {
const childEle = document.getElementById('blocker-div');
if (childEle) {
childEle.parentNode.removeChild(childEle);
}
};
})();

export const createZoomWarningMsg = (function () {
let disableZoomMsg = false;
const setZoomMsg = (boolDisableMsg) => (disableZoomMsg = boolDisableMsg);
Expand All @@ -59,6 +113,7 @@ export const createZoomWarningMsg = (function () {
access to additional zoom levels for free through the {ems}.
Or, you can configure your own map server. Please go to
{ wms } or { configSettings} for more information."
// TODO: [RENAMEME] Need valid URLs
values={{
defaultDistribution: (
<a target="_blank" href="https://www.opensearch.org/downloads/kibana">
Expand Down
12 changes: 11 additions & 1 deletion src/plugins/maps_legacy/public/map/opensearch_dashboards_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
*/

import { EventEmitter } from 'events';
import { createZoomWarningMsg } from './map_messages';
import {
createZoomWarningMsg,
createRegionBlockedWarning,
removeRegionBlockedWarning,
} from './map_messages';
import $ from 'jquery';
import { get, isEqual, escape } from 'lodash';
import { zoomToPrecision } from './zoom_to_precision';
Expand Down Expand Up @@ -606,6 +610,11 @@ export class OpenSearchDashboardsMap extends EventEmitter {
baseLayer.on('loading', () => {
this.emit('baseLayer:loading');
});
baseLayer.on('tileerror', () => {
if (baseLayer._url.includes('search-services.aws.a2z.com')) {
createRegionBlockedWarning();
}
});

this._leafletBaseLayer = baseLayer;
if (settings.options.showZoomMessage) {
Expand Down Expand Up @@ -684,6 +693,7 @@ export class OpenSearchDashboardsMap extends EventEmitter {
}

_updateDesaturation() {
removeRegionBlockedWarning();
const tiles = $('img.leaflet-tile-loaded');
// Don't apply client-side styling to EMS basemaps
if (get(this._baseLayerSettings, 'options.origin') === ORIGIN.EMS) {
Expand Down
40 changes: 38 additions & 2 deletions src/plugins/maps_legacy/public/map/service_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import _ from 'lodash';
import MarkdownIt from 'markdown-it';
import { EMSClient } from '@elastic/ems-client';
import { OpenSearchMapsClient } from '../common/opensearch_maps_client.js';
import { i18n } from '@osd/i18n';
import { getOpenSearchDashboardsVersion } from '../opensearch_dashboards_services';
import { ORIGIN } from '../common/constants/origin';
Expand All @@ -46,13 +47,15 @@ export class ServiceSettings {
this._hasTmsConfigured = typeof tilemapsConfig.url === 'string' && tilemapsConfig.url !== '';

this._showZoomMessage = true;
this._emsClient = new EMSClient({
this._emsClient = null;
this._opensearchMapsClient = new OpenSearchMapsClient({
language: i18n.getLocale(),
appVersion: getOpenSearchDashboardsVersion(),
appName: 'opensearch-dashboards',
fileApiUrl: this._mapConfig.emsFileApiUrl,
tileApiUrl: this._mapConfig.emsTileApiUrl,
landingPageUrl: this._mapConfig.emsLandingPageUrl,
landingPageUrl: '',
manifestServiceUrl: this._mapConfig.opensearchManifestServiceUrl,
// Wrap to avoid errors passing window fetch
fetchFunction: function (...args) {
return fetch(...args);
Expand Down Expand Up @@ -87,6 +90,7 @@ export class ServiceSettings {
}

__debugStubManifestCalls(manifestRetrieval) {
this._emsClient = this._opensearchMapsClient;
const oldGetManifest = this._emsClient.getManifest;
this._emsClient.getManifest = manifestRetrieval;
return {
Expand Down Expand Up @@ -118,11 +122,39 @@ export class ServiceSettings {
};
};

// anyone using this._emsClient should call this method before, to set the right client
async _setMapServices() {
// if client is not null, return immediately.
// Effectively, client creation will be called only once.
if (this._emsClient) {
return;
}
const useOpenSearchMaps = await this._opensearchMapsClient.isEnabled();
if (useOpenSearchMaps) {
// using OpenSearch Maps.
this._emsClient = this._opensearchMapsClient;
} else {
// not using OpenSearch Maps, fallback to default maps.
this._emsClient = new EMSClient({
language: i18n.getLocale(),
appVersion: getOpenSearchDashboardsVersion(),
appName: 'opensearch-dashboards',
fileApiUrl: this._mapConfig.emsFileApiUrl,
tileApiUrl: this._mapConfig.emsTileApiUrl,
landingPageUrl: this._mapConfig.emsLandingPageUrl,
fetchFunction: function (...args) {
return fetch(...args);
},
});
}
}

async getFileLayers() {
if (!this._mapConfig.includeOpenSearchMapsService) {
return [];
}

await this._setMapServices();
const fileLayers = await this._emsClient.getFileLayers();
return fileLayers.map(this._backfillSettings);
}
Expand All @@ -141,6 +173,7 @@ export class ServiceSettings {
allServices.push(tmsService);
}

await this._setMapServices();
if (this._mapConfig.includeOpenSearchMapsService) {
const servicesFromManifest = await this._emsClient.getTMSServices();
const strippedServiceFromManifest = await Promise.all(
Expand Down Expand Up @@ -183,6 +216,7 @@ export class ServiceSettings {
}

async getEMSHotLink(fileLayerConfig) {
await this._setMapServices();
const layer = await this.getFileLayerFromConfig(fileLayerConfig);
return layer ? layer.getEMSHotLink() : null;
}
Expand All @@ -193,6 +227,7 @@ export class ServiceSettings {
}

async _getAttributesForEMSTMSLayer(isDesaturated, isDarkMode) {
await this._setMapServices();
const tmsServices = await this._emsClient.getTMSServices();
const emsTileLayerId = this._mapConfig.emsTileLayerId;
let serviceId;
Expand Down Expand Up @@ -236,6 +271,7 @@ export class ServiceSettings {
}

async _getFileUrlFromEMS(fileLayerConfig) {
await this._setMapServices();
const fileLayers = await this._emsClient.getFileLayers();
const layer = fileLayers.find((fileLayer) => {
const hasIdByName = fileLayer.hasId(fileLayerConfig.name); //legacy
Expand Down
1 change: 1 addition & 0 deletions src/plugins/maps_legacy/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const config: PluginConfigDescriptor<MapsLegacyConfig> = {
tilemap: true,
regionmap: true,
manifestServiceUrl: true,
opensearchManifestServiceUrl: true,
emsFileApiUrl: true,
emsTileApiUrl: true,
emsLandingPageUrl: true,
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/region_map/public/choropleth_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ Make sure the file exists at that location.",
values: { name: name },
}
);
} else if (e.config.url.includes('aws.a2z.com')) {
// AES Region Maps will throw CORS exception when accessed from Embargo Regions.
// OPTIONS will fail before GET. Thus CORS error.
errorMessage = 'The vector map ' + name + ' is not available.';
} else {
errorMessage = i18n.translate(
'regionMap.choroplethLayer.downloadingVectorDataErrorMessage',
Expand Down
23 changes: 0 additions & 23 deletions src/plugins/region_map/public/components/region_map_options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,29 +117,6 @@ function RegionMapOptions(props: RegionMapOptionsProps) {
label={i18n.translate('regionMap.visParams.vectorMapLabel', {
defaultMessage: 'Vector map',
})}
labelAppend={
stateParams.emsHotLink && (
<EuiText size="xs">
<EuiLink
href={stateParams.emsHotLink}
target="_blank"
title={i18n.translate('regionMap.visParams.previewOnEMSLinkTitle', {
defaultMessage: 'Preview {selectedLayerName} on the OpenSearch Maps Service',
values: {
selectedLayerName:
stateParams.selectedLayer && stateParams.selectedLayer.name,
},
})}
>
<FormattedMessage
id="regionMap.visParams.previewOnEMSLinkText"
defaultMessage="Preview on EMS"
/>{' '}
<EuiIcon type="popout" size="s" />
</EuiLink>
</EuiText>
)
}
options={vectorLayerOptions}
paramName="selectedLayer"
value={stateParams.selectedLayer && stateParams.selectedLayer.layerId}
Expand Down

0 comments on commit 19e3340

Please sign in to comment.