From 2af3308df451834f13b172a90bcecd069a9e9d4b Mon Sep 17 00:00:00 2001 From: Naveen Tatikonda Date: Tue, 11 Apr 2023 18:37:52 -0500 Subject: [PATCH] Toast Warning Message if OpenSearch base map is used in conflicting regions (#382) * Toast Warning Message if OpenSearch base map is used in conflicting regions Signed-off-by: Naveen Tatikonda * Add Custom map link to Toast Notification Message Signed-off-by: Naveen Tatikonda * Address Review Comments Signed-off-by: Naveen Tatikonda --------- Signed-off-by: Naveen Tatikonda (cherry picked from commit 63d7232370544449c2c7ebef1e54845e1d8710b1) --- CHANGELOG.md | 1 + .../map_container/map_container.tsx | 19 ++++++- .../map_container/maps_messages.tsx | 25 ++++++++++ public/model/OSMLayerFunctions.ts | 50 +++++++++++++++---- public/model/layerRenderController.ts | 10 ++-- 5 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 public/components/map_container/maps_messages.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index ae38669f..e0e26957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), * Add filter bar to display global geospatial filters ([#371](https://github.com/opensearch-project/dashboards-maps/pull/371)) * Change font opacity along with OpenSearch base map layer ([#373](https://github.com/opensearch-project/dashboards-maps/pull/373)) * Add before layer id when adding documents label ([#387](https://github.com/opensearch-project/dashboards-maps/pull/387)) +* Toast Warning Message if OpenSearch base map is used in conflicting regions ([#382](https://github.com/opensearch-project/dashboards-maps/pull/382)) ### Bug Fixes * Fix property value undefined check ([#276](https://github.com/opensearch-project/dashboards-maps/pull/276)) diff --git a/public/components/map_container/map_container.tsx b/public/components/map_container/map_container.tsx index f87898fd..98c7bd6d 100644 --- a/public/components/map_container/map_container.tsx +++ b/public/components/map_container/map_container.tsx @@ -33,6 +33,7 @@ import { SpatialFilterToolbar } from '../toolbar/spatial_filter/filter_toolbar'; import { DrawFilterShapeHelper } from '../toolbar/spatial_filter/display_draw_helper'; import { ShapeFilter } from '../../../../../src/plugins/data/common'; import { DashboardProps } from '../map_page/map_page'; +import { MapsServiceErrorMsg } from './maps_messages'; interface MapContainerProps { setLayers: (layers: MapLayerSpecification[]) => void; @@ -49,6 +50,13 @@ interface MapContainerProps { addSpatialFilter: (shape: ShapeFilter, label: string | null, relation: GeoShapeRelation) => void; } +export class MapsServiceError extends Error { + constructor(message?: string) { + super(message); + this.name = 'MapsServiceError'; + } +} + export const MapContainer = ({ setLayers, layers, @@ -64,6 +72,13 @@ export const MapContainer = ({ addSpatialFilter, }: MapContainerProps) => { const { services } = useOpenSearchDashboards(); + + function onError(e: unknown) { + if (e instanceof MapsServiceError) { + services.toastNotifications.addWarning(MapsServiceErrorMsg); + } + } + const mapContainer = useRef(null); const [mounted, setMounted] = useState(false); const [zoom, setZoom] = useState(MAP_INITIAL_STATE.zoom); @@ -173,7 +188,7 @@ export const MapContainer = ({ if (isUpdatingLayerRender || isReadOnlyMode) { if (selectedLayerConfig) { if (baseLayerTypeLookup[selectedLayerConfig.type]) { - handleBaseLayerRender(selectedLayerConfig, maplibreRef); + handleBaseLayerRender(selectedLayerConfig, maplibreRef, onError); } else { updateIndexPatterns(); handleDataLayerRender( @@ -186,7 +201,7 @@ export const MapContainer = ({ setSelectedLayerConfig(undefined); } else { renderDataLayers(layers, mapState, services, maplibreRef, dashboardProps); - renderBaseLayers(layers, maplibreRef); + renderBaseLayers(layers, maplibreRef, onError); // Because of async layer rendering, layers order is not guaranteed, so we need to order layers // after all layers are rendered. maplibreRef.current!.once('idle', orderLayersAfterRenderLoaded); diff --git a/public/components/map_container/maps_messages.tsx b/public/components/map_container/maps_messages.tsx new file mode 100644 index 00000000..02d0d058 --- /dev/null +++ b/public/components/map_container/maps_messages.tsx @@ -0,0 +1,25 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { EuiLink } from '@elastic/eui'; +import React from 'react'; +import { ToastInputFields } from '../../../../../src/core/public'; +import { toMountPoint } from '../../../../../src/plugins/opensearch_dashboards_react/public'; + +export const MapsServiceErrorMsg: ToastInputFields = { + title: 'The OpenSearch Maps Service is currently not available in your region', + text: toMountPoint( +

+ You can configure OpenSearch Dashboards to use a{' '} + + custom map + {' '} + server for dashboards maps. +

+ ), +}; diff --git a/public/model/OSMLayerFunctions.ts b/public/model/OSMLayerFunctions.ts index 972e6218..989d2983 100644 --- a/public/model/OSMLayerFunctions.ts +++ b/public/model/OSMLayerFunctions.ts @@ -10,6 +10,17 @@ import { } from './map/layer_operations'; import { getMapLanguage } from '../../common/util'; import { MaplibreRef } from './layersFunctions'; +import { MapsServiceError } from '../components/map_container/map_container'; + +const fetchDataLayer = (dataUrl: string) => { + return fetch(dataUrl) + .then(() => true) + .catch((error) => { + // eslint-disable-next-line no-console + console.log('error', error); + throw new MapsServiceError(error.message); + }); +}; // Fetch style layers from OpenSearch vector tile service const fetchStyleLayers = (url: string) => { @@ -19,6 +30,7 @@ const fetchStyleLayers = (url: string) => { .catch((error) => { // eslint-disable-next-line no-console console.log('error', error); + throw new MapsServiceError(error.message); }); }; @@ -43,28 +55,46 @@ const setLanguage = (maplibreRef: MaplibreRef, styleLayer: LayerSpecification) = } }; -const addNewLayer = (layerConfig: OSMLayerSpecification, maplibreRef: MaplibreRef) => { +const addNewLayer = ( + layerConfig: OSMLayerSpecification, + maplibreRef: MaplibreRef, + onError: Function +) => { if (maplibreRef.current) { const maplibre = maplibreRef.current; const { id, source, style } = layerConfig; - addOSMLayerSource(maplibre, id, source.dataURL); - fetchStyleLayers(style?.styleURL).then((styleLayers: LayerSpecification[]) => { - styleLayers.forEach((layer) => { - const styleLayer = getOSMStyleLayerWithMapLayerId(id, layer); - addOSMStyleLayer(maplibre, layerConfig, styleLayer); - setLanguage(maplibreRef, styleLayer); + fetchDataLayer(source.dataURL) + .then(() => { + addOSMLayerSource(maplibre, id, source.dataURL); + fetchStyleLayers(style?.styleURL) + .then((styleLayers: LayerSpecification[]) => { + styleLayers.forEach((layer) => { + const styleLayer = getOSMStyleLayerWithMapLayerId(id, layer); + addOSMStyleLayer(maplibre, layerConfig, styleLayer); + setLanguage(maplibreRef, styleLayer); + }); + }) + .catch((e) => { + if (onError) { + onError(e); + } + }); + }) + .catch((e) => { + if (onError) { + onError(e); + } }); - }); } }; // Functions for OpenSearch maps vector tile layer export const OSMLayerFunctions = { - render: (maplibreRef: MaplibreRef, layerConfig: OSMLayerSpecification) => { + render: (maplibreRef: MaplibreRef, layerConfig: OSMLayerSpecification, onError: Function) => { // If layer already exist in maplibre source, update layer config // else add new layer. return hasLayer(maplibreRef.current!, layerConfig.id) ? updateLayerConfig(layerConfig, maplibreRef) - : addNewLayer(layerConfig, maplibreRef); + : addNewLayer(layerConfig, maplibreRef, onError); }, }; diff --git a/public/model/layerRenderController.ts b/public/model/layerRenderController.ts index b7527f8c..e4e8a2eb 100644 --- a/public/model/layerRenderController.ts +++ b/public/model/layerRenderController.ts @@ -202,9 +202,10 @@ const getGlobalStates = (mapState: MapState, dashboardProps?: DashboardProps): M export const handleBaseLayerRender = ( layer: MapLayerSpecification, - maplibreRef: MaplibreRef + maplibreRef: MaplibreRef, + onError: Function ): void => { - layersFunctionMap[layer.type].render(maplibreRef, layer); + layersFunctionMap[layer.type].render(maplibreRef, layer, onError); }; export const renderDataLayers = ( @@ -221,10 +222,11 @@ export const renderDataLayers = ( export const renderBaseLayers = ( layers: MapLayerSpecification[], - maplibreRef: MaplibreRef + maplibreRef: MaplibreRef, + onError: Function ): void => { getBaseLayers(layers).forEach((layer) => { - handleBaseLayerRender(layer, maplibreRef); + handleBaseLayerRender(layer, maplibreRef, onError); }); };