From e482029fca2eac6013637c08a9a79f9783a084d2 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 08:59:23 -0700 Subject: [PATCH 01/17] Update ems utils to better handle no service results. Prevent excess attribution errors --- .../sources/ems_tms_source/ems_tms_source.js | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js index c43449a1367db..34cfda7bd2c52 100644 --- a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js @@ -71,9 +71,18 @@ export class EMSTMSSource extends TMSSource { } _getTMSOptions() { - return this._emsTileServices.find(service => { + if(!this._emsTileServices || !this._emsTileServices.length) { + return; + } + + const emsTmsService = this._emsTileServices.find(service => { return service.id === this._descriptor.id; }); + if (!emsTmsService) { + console.error(`EMS TMS Service: ${this._descriptor.id} currently unavailable`); + return; + } + return emsTmsService; } _createDefaultLayerDescriptor(options) { @@ -95,25 +104,33 @@ export class EMSTMSSource extends TMSSource { } async getAttributions() { - const service = this._getTMSOptions(); - const attributions = service.attributionMarkdown.split('|'); - - return attributions.map((attribution) => { - attribution = attribution.trim(); - //this assumes attribution is plain markdown link - const extractLink = /\[(.*)\]\((.*)\)/; - const result = extractLink.exec(attribution); - return { - label: result ? result[1] : null, - url: result ? result[2] : null - }; - }); + let service; + let attributions; + try { + service = this._getTMSOptions(); + attributions = service.attributionMarkdown.split('|'); + } catch (e) { + console.warn(`Error obtaining attributions: ${e}`); + } + return attributions + ? attributions.map((attribution) => { + attribution = attribution.trim(); + //this assumes attribution is plain markdown link + const extractLink = /\[(.*)\]\((.*)\)/; + const result = extractLink.exec(attribution); + return { + label: result ? result[1] : null, + url: result ? result[2] : null + }; + }) + : ''; } getUrlTemplate() { const service = this._getTMSOptions(); + if (!service || !service.url) { + throw new Error('Can not generate EMS TMS url template'); + } return service.url; } - - } From 6b911c306a3c4049f207bc73439fccd1722c2501 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:02:14 -0700 Subject: [PATCH 02/17] Update tile layer sync to return promise and handle errors related to both obtaining url and tile loading --- .../gis/public/shared/layers/tile_layer.js | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index 0519cde0faf5d..b159f2913ea09 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -13,6 +13,7 @@ import _ from 'lodash'; export class TileLayer extends ALayer { static type = "TILE"; + TMS_LOAD_TIMEOUT = 32000; constructor({ layerDescriptor, source, style }) { super({ layerDescriptor, source, style }); @@ -32,14 +33,48 @@ export class TileLayer extends ALayer { return tileLayerDescriptor; } + _tileLoadErrorTracker(map, url) { + let tileLoadCount = 0; + map.on('tileload', ({ tile }) => tile && tileLoadCount++); - syncLayerWithMB(mbMap) { + return new Promise((resolve, reject) => { + const tileLoadTimer = setTimeout(() => { + map.off('sourcedata'); + if (!tileLoadCount) { + try { + throw new Error(`Tiles from "${url}" could not be loaded`); + } catch (e) { + reject(e); + } + } else { + resolve(); + } + }, this.TMS_LOAD_TIMEOUT); + if (tileLoadCount) { + clearTimeout(tileLoadTimer); + resolve(); + } + }); + } + async syncLayerWithMB(mbMap) { const source = mbMap.getSource(this.getId()); const layerId = this.getId() + '_raster'; - if (!source) { - const url = this._source.getUrlTemplate(); - mbMap.addSource(this.getId(), { + + if (source) { + return; + } + + let url; + return new Promise((resolve, reject) => { + try { + url = this._source.getUrlTemplate(); + } catch (e) { + reject(e); + } + + const sourceId = this.getId(); + mbMap.addSource(sourceId, { type: 'raster', tiles: [url], tileSize: 256, @@ -49,15 +84,20 @@ export class TileLayer extends ALayer { mbMap.addLayer({ id: layerId, type: 'raster', - source: this.getId(), + source: sourceId, minzoom: 0, maxzoom: 22, }); - } - - mbMap.setLayoutProperty(layerId, 'visibility', this.isVisible() ? 'visible' : 'none'); - mbMap.setLayerZoomRange(layerId, this._descriptor.minZoom, this._descriptor.maxZoom); - this._style && this._style.setMBPaintProperties(mbMap, layerId); + resolve(); + }).then(() => this._tileLoadErrorTracker(mbMap, url) + ).then(() => { + mbMap.setLayoutProperty(layerId, 'visibility', this.isVisible() + ? 'visible' + : 'none'); + mbMap.setLayerZoomRange(layerId, this._descriptor.minZoom, + this._descriptor.maxZoom); + this._style && this._style.setMBPaintProperties(mbMap, layerId); + }); } getIcon() { From abafa1cdc1731baaed0faa732817b03cee72dec8 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:04:10 -0700 Subject: [PATCH 03/17] Add flow for updating tms layers with error status/message --- x-pack/plugins/gis/public/actions/store_actions.js | 11 +++++++++++ x-pack/plugins/gis/public/components/map/mb/index.js | 7 +++++-- x-pack/plugins/gis/public/store/map.js | 10 ++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/gis/public/actions/store_actions.js b/x-pack/plugins/gis/public/actions/store_actions.js index d255e5d7db850..8c03a5ca010b0 100644 --- a/x-pack/plugins/gis/public/actions/store_actions.js +++ b/x-pack/plugins/gis/public/actions/store_actions.js @@ -21,6 +21,7 @@ import { timeService } from '../kibana_services'; export const SET_SELECTED_LAYER = 'SET_SELECTED_LAYER'; export const UPDATE_LAYER_ORDER = 'UPDATE_LAYER_ORDER'; export const ADD_LAYER = 'ADD_LAYER'; +export const SET_TMS_ERROR_STATUS = 'SET_TMS_ERROR_STATUS'; export const ADD_WAITING_FOR_MAP_READY_LAYER = 'ADD_WAITING_FOR_MAP_READY_LAYER'; export const CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST = 'CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST'; export const REMOVE_LAYER = 'REMOVE_LAYER'; @@ -109,6 +110,16 @@ export function addLayer(layerDescriptor) { }; } +export function setTmsErrorStatus(layerDescriptor) { + return dispatch => { + dispatch(clearTemporaryLayers()); + dispatch({ + type: SET_TMS_ERROR_STATUS, + layer: layerDescriptor, + }); + }; +} + export function toggleLayerVisible(layerId) { return { type: TOGGLE_LAYER_VISIBLE, diff --git a/x-pack/plugins/gis/public/components/map/mb/index.js b/x-pack/plugins/gis/public/components/map/mb/index.js index bc4418ba2005a..a910bd10d38c9 100644 --- a/x-pack/plugins/gis/public/components/map/mb/index.js +++ b/x-pack/plugins/gis/public/components/map/mb/index.js @@ -12,7 +12,8 @@ import { mapDestroyed, setMouseCoordinates, clearMouseCoordinates, - clearGoto + clearGoto, + setTmsErrorStatus, } from '../../../actions/store_actions'; import { getLayerList, getMapReady, getGoto } from "../../../selectors/map_selectors"; @@ -45,7 +46,9 @@ function mapDispatchToProps(dispatch) { }, clearGoto: () => { dispatch(clearGoto()); - } + }, + setTmsErrorStatus: layerDescriptor => + dispatch(setTmsErrorStatus(layerDescriptor)) }; } diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js index cf32464034a9c..653a4eb82527d 100644 --- a/x-pack/plugins/gis/public/store/map.js +++ b/x-pack/plugins/gis/public/store/map.js @@ -11,6 +11,7 @@ import { LAYER_DATA_LOAD_ENDED, LAYER_DATA_LOAD_ERROR, ADD_LAYER, + SET_TMS_ERROR_STATUS, ADD_WAITING_FOR_MAP_READY_LAYER, CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, REMOVE_LAYER, @@ -214,6 +215,15 @@ export function map(state = INITIAL_STATE, action) { return { ...state, layerList: newLayerList }; } return state; + case SET_TMS_ERROR_STATUS: + const tmsErrorLayer = state.layerList.find(({ id }) => id === action.layer.id); + const stateWithTmsError = tmsErrorLayer + ? updateLayerInList( + updateLayerInList(state, tmsErrorLayer.id, 'errorState', + action.layer.errorState), tmsErrorLayer.id, 'errorMessage', + action.layer.errorMessage) + : state; + return stateWithTmsError; case ADD_LAYER: return { ...state, From ad4184b1f210583df6d02f9403dbed6ef683f2c5 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:06:15 -0700 Subject: [PATCH 04/17] Handle promises, if returned, on syncLayerWithMB. Update TMS error status --- .../gis/public/components/map/mb/view.js | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/gis/public/components/map/mb/view.js b/x-pack/plugins/gis/public/components/map/mb/view.js index b8033c7e54ed4..e32e1088ad520 100644 --- a/x-pack/plugins/gis/public/components/map/mb/view.js +++ b/x-pack/plugins/gis/public/components/map/mb/view.js @@ -185,9 +185,26 @@ export class MBMapContainer extends React.Component { if (!isMapReady) { return; } + removeOrphanedSourcesAndLayers(this._mbMap, layerList); - layerList.forEach((layer) => { - layer.syncLayerWithMB(this._mbMap); + layerList.forEach(layer => { + if (!layer.dataHasLoadError()) { + Promise.resolve(layer.syncLayerWithMB(this._mbMap)) + .catch(({ message }) => { + switch(layer._descriptor.type) { + case 'TILE': + console.warn(`Sync error retrieving tiles from TMS: ${message}`); + this.props.setTmsErrorStatus({ + id: layer.getId(), + errorState: true, + errorMessage: message, + }); + break; + default: + console.warn(`Layer sync error: ${message}`); + } + }); + } }); syncLayerOrder(this._mbMap, layerList); }; From 58651ae4f212fe2006ae19affe06ddf827f656b1 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:07:22 -0700 Subject: [PATCH 05/17] Exclude layers that mapbox didn't add to map but are tracked in layer list from reordering logic --- x-pack/plugins/gis/public/components/map/mb/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/gis/public/components/map/mb/utils.js b/x-pack/plugins/gis/public/components/map/mb/utils.js index 4403a992a4eb0..fe08537c85131 100644 --- a/x-pack/plugins/gis/public/components/map/mb/utils.js +++ b/x-pack/plugins/gis/public/components/map/mb/utils.js @@ -63,7 +63,8 @@ export function syncLayerOrder(mbMap, layerList) { const mbLayers = mbMap.getStyle().layers.slice(); const currentLayerOrder = _.uniq( // Consolidate layers and remove suffix mbLayers.map(({ id }) => id.substring(0, id.lastIndexOf('_')))); - const newLayerOrder = layerList.map(l => l.getId()); + const newLayerOrder = layerList.map(l => l.getId()) + .filter(layerId => currentLayerOrder.includes(layerId)); let netPos = 0; let netNeg = 0; const movementArr = currentLayerOrder.reduce((accu, id, idx) => { From bfc1db4a522e1d1b6501e7ee7d19ff344e3f06f7 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:10:12 -0700 Subject: [PATCH 06/17] Move datarequest handling to vector layer. Use relevant data load/error logic for tile and vector layers --- .../plugins/gis/public/shared/layers/layer.js | 21 ++++------------ .../gis/public/shared/layers/tile_layer.js | 11 +++++++++ .../gis/public/shared/layers/vector_layer.js | 24 +++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index 122a605e6ef89..9c7f112d694e4 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -6,7 +6,6 @@ import _ from 'lodash'; import turf from 'turf'; import turfBooleanContains from '@turf/boolean-contains'; -import { DataRequest } from './util/data_request'; const SOURCE_UPDATE_REQUIRED = true; const NO_SOURCE_UPDATE_REQUIRED = false; @@ -17,12 +16,6 @@ export class ALayer { this._descriptor = layerDescriptor; this._source = source; this._style = style; - - if (this._descriptor.dataRequests) { - this._dataRequests = this._descriptor.dataRequests.map(dataRequest => new DataRequest(dataRequest)); - } else { - this._dataRequests = []; - } } static getBoundDataForSource(mbMap, sourceId) { @@ -33,7 +26,7 @@ export class ALayer { static createDescriptor(options) { const layerDescriptor = {}; - layerDescriptor.dataRequests = []; + layerDescriptor.type = undefined; layerDescriptor.id = Math.random().toString(36).substr(2, 5); layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null; layerDescriptor.minZoom = _.get(options, 'minZoom', 0); @@ -137,16 +130,16 @@ export class ALayer { } isLayerLoading() { - return this._dataRequests.some(dataRequest => dataRequest.isLoading()); + console.warn(`Layer load status not implemented for ${this._descriptor.type}`); } dataHasLoadError() { - return this._dataRequests.some(dataRequest => dataRequest.hasLoadError()); + console.warn(`Load error status not implemented for ${this._descriptor.type}`); + return false; } getDataLoadError() { - const loadErrors = this._dataRequests.filter(dataRequest => dataRequest.hasLoadError()); - return loadErrors.join(',');//todo + console.warn(`Load error not implemented for ${this._descriptor.type}`); } toLayerDescriptor() { @@ -196,10 +189,6 @@ export class ALayer { return style.renderEditor(options); } - getSourceDataRequest() { - return this._dataRequests.find(dataRequest => dataRequest.getDataId() === 'source'); - } - getIndexPatternIds() { return []; } diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index b159f2913ea09..06b3ba0863191 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -107,5 +107,16 @@ export class TileLayer extends ALayer { /> ); } + isLayerLoading() { + return false; + } + + dataHasLoadError() { + return this._descriptor.errorState; + } + + getDataLoadError() { + return this.dataHasLoadError() ? this._descriptor.errorMessage : ''; + } } diff --git a/x-pack/plugins/gis/public/shared/layers/vector_layer.js b/x-pack/plugins/gis/public/shared/layers/vector_layer.js index b6cc41c77d828..20082436b2f3c 100644 --- a/x-pack/plugins/gis/public/shared/layers/vector_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/vector_layer.js @@ -11,6 +11,7 @@ import ReactDOM from 'react-dom'; import { ALayer } from './layer'; import { VectorStyle } from './styles/vector_style'; import { LeftInnerJoin } from './joins/left_inner_join'; +import { DataRequest } from './util/data_request'; import { FeatureTooltip } from 'plugins/gis/components/map/feature_tooltip'; import { store } from '../../store/store'; @@ -46,6 +47,7 @@ export class VectorLayer extends ALayer { ]; const layerDescriptor = super.createDescriptor(options); layerDescriptor.type = VectorLayer.type; + layerDescriptor.dataRequests = []; if (!options.style) { layerDescriptor.style = VectorStyle.createDescriptor({ fillColor: { @@ -86,6 +88,11 @@ export class VectorLayer extends ALayer { this._joins.push(new LeftInnerJoin(joinDescriptor)); }); } + if (this._descriptor.dataRequests) { + this._dataRequests = this._descriptor.dataRequests.map(dataRequest => new DataRequest(dataRequest)); + } else { + this._dataRequests = []; + } } destroy() { @@ -172,6 +179,23 @@ export class VectorLayer extends ALayer { return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); } + getSourceDataRequest() { + return this._dataRequests.find(dataRequest => dataRequest.getDataId() === 'source'); + } + + isLayerLoading() { + return this._dataRequests.some(dataRequest => dataRequest.isLoading()); + } + + dataHasLoadError() { + return this._dataRequests.some(dataRequest => dataRequest.hasLoadError()); + } + + getDataLoadError() { + const loadErrors = this._dataRequests.filter(dataRequest => dataRequest.hasLoadError()); + return loadErrors.join(',');//todo + } + async _canSkipSourceUpdate(source, sourceDataId, filters) { const timeAware = await source.isTimeAware(); const refreshTimerAware = await source.isRefreshTimerAware(); From 4a6f50e7c8df27b6fcbaf93b60710951969d47b8 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 09:10:51 -0700 Subject: [PATCH 07/17] Don't try to get attributions on errored layer --- x-pack/plugins/gis/public/shared/layers/layer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index 9c7f112d694e4..f29f8b5a19ab1 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -58,7 +58,10 @@ export class ALayer { } async getAttributions() { - return await this._source.getAttributions(); + if (!this.dataHasLoadError()) { + return await this._source.getAttributions(); + } + return ''; } getLabel() { From 3b2bba53f679ad67cbadf904fa053f9fcaff8bd3 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Wed, 16 Jan 2019 10:10:16 -0700 Subject: [PATCH 08/17] Handle 'includeElasticMapsService' configuration --- x-pack/plugins/gis/server/routes.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/x-pack/plugins/gis/server/routes.js b/x-pack/plugins/gis/server/routes.js index 01576da3c7c1f..d23bb1dd2d446 100644 --- a/x-pack/plugins/gis/server/routes.js +++ b/x-pack/plugins/gis/server/routes.js @@ -79,6 +79,13 @@ export function initRoutes(server, licenseUid) { async function getEMSResources(licenseUid) { + if (!mapConfig.includeElasticMapsService) { + return { + fileLayers: [], + tmsServices: [] + }; + } + emsClient.addQueryParams({ license: licenseUid }); const fileLayerObjs = await emsClient.getFileLayers(); const tmsServicesObjs = await emsClient.getTMSServices(); From 43a021fdadcd18495debce9fd2f73f1568f787ae Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 12:39:53 -0700 Subject: [PATCH 09/17] Move data requests back to layer level for heatmap usage --- .../plugins/gis/public/shared/layers/layer.js | 22 ++++++++++++--- .../gis/public/shared/layers/tile_layer.js | 8 ------ .../gis/public/shared/layers/vector_layer.js | 28 ------------------- 3 files changed, 18 insertions(+), 40 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index f29f8b5a19ab1..3685f4f0e7676 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -6,6 +6,7 @@ import _ from 'lodash'; import turf from 'turf'; import turfBooleanContains from '@turf/boolean-contains'; +import { DataRequest } from './util/data_request'; const SOURCE_UPDATE_REQUIRED = true; const NO_SOURCE_UPDATE_REQUIRED = false; @@ -16,6 +17,11 @@ export class ALayer { this._descriptor = layerDescriptor; this._source = source; this._style = style; + if (this._descriptor.dataRequests) { + this._dataRequests = this._descriptor.dataRequests.map(dataRequest => new DataRequest(dataRequest)); + } else { + this._dataRequests = []; + } } static getBoundDataForSource(mbMap, sourceId) { @@ -33,6 +39,7 @@ export class ALayer { layerDescriptor.maxZoom = _.get(options, 'maxZoom', 24); layerDescriptor.source = options.source; layerDescriptor.sourceDescriptor = options.sourceDescriptor; + layerDescriptor.dataRequests = []; layerDescriptor.visible = options.visible || true; layerDescriptor.temporary = options.temporary || false; layerDescriptor.style = options.style || {}; @@ -132,17 +139,24 @@ export class ALayer { return this._source.renderSourceSettingsEditor({ onChange }); } + _findDataRequestForSource(sourceDataId) { + return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); + } + + getSourceDataRequest() { + return this._dataRequests.find(dataRequest => dataRequest.getDataId() === 'source'); + } + isLayerLoading() { - console.warn(`Layer load status not implemented for ${this._descriptor.type}`); + return this._dataRequests.some(dataRequest => dataRequest.isLoading()); } dataHasLoadError() { - console.warn(`Load error status not implemented for ${this._descriptor.type}`); - return false; + return this._descriptor.errorState; } getDataLoadError() { - console.warn(`Load error not implemented for ${this._descriptor.type}`); + return this.dataHasLoadError() ? this._descriptor.errorMessage : ''; } toLayerDescriptor() { diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index 06b3ba0863191..55d188377850f 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -111,12 +111,4 @@ export class TileLayer extends ALayer { return false; } - dataHasLoadError() { - return this._descriptor.errorState; - } - - getDataLoadError() { - return this.dataHasLoadError() ? this._descriptor.errorMessage : ''; - } - } diff --git a/x-pack/plugins/gis/public/shared/layers/vector_layer.js b/x-pack/plugins/gis/public/shared/layers/vector_layer.js index 20082436b2f3c..114b2b3bdb28b 100644 --- a/x-pack/plugins/gis/public/shared/layers/vector_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/vector_layer.js @@ -11,7 +11,6 @@ import ReactDOM from 'react-dom'; import { ALayer } from './layer'; import { VectorStyle } from './styles/vector_style'; import { LeftInnerJoin } from './joins/left_inner_join'; -import { DataRequest } from './util/data_request'; import { FeatureTooltip } from 'plugins/gis/components/map/feature_tooltip'; import { store } from '../../store/store'; @@ -47,7 +46,6 @@ export class VectorLayer extends ALayer { ]; const layerDescriptor = super.createDescriptor(options); layerDescriptor.type = VectorLayer.type; - layerDescriptor.dataRequests = []; if (!options.style) { layerDescriptor.style = VectorStyle.createDescriptor({ fillColor: { @@ -88,11 +86,6 @@ export class VectorLayer extends ALayer { this._joins.push(new LeftInnerJoin(joinDescriptor)); }); } - if (this._descriptor.dataRequests) { - this._dataRequests = this._descriptor.dataRequests.map(dataRequest => new DataRequest(dataRequest)); - } else { - this._dataRequests = []; - } } destroy() { @@ -175,27 +168,6 @@ export class VectorLayer extends ALayer { return indexPatternIds; } - _findDataRequestForSource(sourceDataId) { - return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); - } - - getSourceDataRequest() { - return this._dataRequests.find(dataRequest => dataRequest.getDataId() === 'source'); - } - - isLayerLoading() { - return this._dataRequests.some(dataRequest => dataRequest.isLoading()); - } - - dataHasLoadError() { - return this._dataRequests.some(dataRequest => dataRequest.hasLoadError()); - } - - getDataLoadError() { - const loadErrors = this._dataRequests.filter(dataRequest => dataRequest.hasLoadError()); - return loadErrors.join(',');//todo - } - async _canSkipSourceUpdate(source, sourceDataId, filters) { const timeAware = await source.isTimeAware(); const refreshTimerAware = await source.isRefreshTimerAware(); From ab80f125d2ec879b408d3e4d466c0d1fa6304e67 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 12:41:19 -0700 Subject: [PATCH 10/17] Update all layers to set top-level layer error status and message. Consolidate redundant code --- .../gis/public/actions/store_actions.js | 5 +- .../gis/public/components/map/mb/index.js | 4 +- .../gis/public/components/map/mb/view.js | 6 +- x-pack/plugins/gis/public/store/map.js | 74 +++++++------------ 4 files changed, 34 insertions(+), 55 deletions(-) diff --git a/x-pack/plugins/gis/public/actions/store_actions.js b/x-pack/plugins/gis/public/actions/store_actions.js index 8c03a5ca010b0..3d1c9fe6dff99 100644 --- a/x-pack/plugins/gis/public/actions/store_actions.js +++ b/x-pack/plugins/gis/public/actions/store_actions.js @@ -110,12 +110,13 @@ export function addLayer(layerDescriptor) { }; } -export function setTmsErrorStatus(layerDescriptor) { +export function setTmsErrorStatus(id, errorMessage) { return dispatch => { dispatch(clearTemporaryLayers()); dispatch({ type: SET_TMS_ERROR_STATUS, - layer: layerDescriptor, + layerId: id, + errorMessage, }); }; } diff --git a/x-pack/plugins/gis/public/components/map/mb/index.js b/x-pack/plugins/gis/public/components/map/mb/index.js index a910bd10d38c9..65416f17606c1 100644 --- a/x-pack/plugins/gis/public/components/map/mb/index.js +++ b/x-pack/plugins/gis/public/components/map/mb/index.js @@ -47,8 +47,8 @@ function mapDispatchToProps(dispatch) { clearGoto: () => { dispatch(clearGoto()); }, - setTmsErrorStatus: layerDescriptor => - dispatch(setTmsErrorStatus(layerDescriptor)) + setTmsErrorStatus: (id, msg) => + dispatch(setTmsErrorStatus(id, msg)) }; } diff --git a/x-pack/plugins/gis/public/components/map/mb/view.js b/x-pack/plugins/gis/public/components/map/mb/view.js index e32e1088ad520..d7639bdaa7810 100644 --- a/x-pack/plugins/gis/public/components/map/mb/view.js +++ b/x-pack/plugins/gis/public/components/map/mb/view.js @@ -194,11 +194,7 @@ export class MBMapContainer extends React.Component { switch(layer._descriptor.type) { case 'TILE': console.warn(`Sync error retrieving tiles from TMS: ${message}`); - this.props.setTmsErrorStatus({ - id: layer.getId(), - errorState: true, - errorMessage: message, - }); + this.props.setTmsErrorStatus(layer.getId(), message); break; default: console.warn(`Layer sync error: ${message}`); diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js index 653a4eb82527d..3ff4017096ac4 100644 --- a/x-pack/plugins/gis/public/store/map.js +++ b/x-pack/plugins/gis/public/store/map.js @@ -135,8 +135,11 @@ export function map(state = INITIAL_STATE, action) { }; case LAYER_DATA_LOAD_STARTED: return updateWithDataRequest(state, action); + case SET_TMS_ERROR_STATUS: + return setErrorStatus(state, action); case LAYER_DATA_LOAD_ERROR: - return updateWithDataLoadError(state, action); + return resetDataRequest( + setErrorStatus(state, action), action); case LAYER_DATA_LOAD_ENDED: return updateWithDataResponse(state, action); case TOUCH_LAYER: @@ -215,15 +218,6 @@ export function map(state = INITIAL_STATE, action) { return { ...state, layerList: newLayerList }; } return state; - case SET_TMS_ERROR_STATUS: - const tmsErrorLayer = state.layerList.find(({ id }) => id === action.layer.id); - const stateWithTmsError = tmsErrorLayer - ? updateLayerInList( - updateLayerInList(state, tmsErrorLayer.id, 'errorState', - action.layer.errorState), tmsErrorLayer.id, 'errorMessage', - action.layer.errorMessage) - : state; - return stateWithTmsError; case ADD_LAYER: return { ...state, @@ -282,6 +276,15 @@ export function map(state = INITIAL_STATE, action) { } } +function setErrorStatus(state, { layerId, errorMessage }) { + const tmsErrorLayer = state.layerList.find(({ id }) => id === layerId); + return tmsErrorLayer + ? updateLayerInList( + updateLayerInList(state, tmsErrorLayer.id, 'errorState', true), + tmsErrorLayer.id, 'errorMessage', errorMessage) + : state; +} + function findDataRequest(layerDescriptor, dataRequestAction) { if (!layerDescriptor.dataRequests) { @@ -295,16 +298,9 @@ function findDataRequest(layerDescriptor, dataRequestAction) { function updateWithDataRequest(state, action) { + let dataRequest = getValidDataRequest(state, action, false); const layerRequestingData = findLayerById(state, action.layerId); - if (!layerRequestingData) { - return state; - } - - if (!layerRequestingData.dataRequests) { - layerRequestingData.dataRequests = []; - } - let dataRequest = findDataRequest(layerRequestingData, action); if (!dataRequest) { dataRequest = { dataId: action.dataId @@ -320,38 +316,29 @@ function updateWithDataRequest(state, action) { } function updateWithDataResponse(state, action) { - const layerReceivingData = findLayerById(state, action.layerId); - if (!layerReceivingData) { - return state; - } - - - const dataRequest = findDataRequest(layerReceivingData, action); - if (!dataRequest) { - throw new Error('Data request should be initialized. Cannot call stopLoading before startLoading'); - } - - if ( - dataRequest.dataRequestToken && - dataRequest.dataRequestToken !== action.requestToken - ) { - // ignore responses to outdated requests - return { ...state }; - } + const dataRequest = getValidDataRequest(state, action); + if (!dataRequest) { return state; } dataRequest.data = action.data; dataRequest.dataMeta = { ...dataRequest.dataMetaAtStart, ...action.meta }; dataRequest.dataMetaAtStart = null; + return resetDataRequest(state, action, dataRequest); +} + +function resetDataRequest(state, action, request) { + const dataRequest = request || getValidDataRequest(state, action); + if (!dataRequest) { return state; } + dataRequest.dataRequestToken = null; dataRequest.dataId = action.dataId; const layerList = [...state.layerList]; return { ...state, layerList }; } -function updateWithDataLoadError(state, action) { +function getValidDataRequest(state, action, checkRequestToken = true) { const layer = findLayerById(state, action.layerId); if (!layer) { - return state; + return; } const dataRequest = findDataRequest(layer, action); @@ -360,19 +347,14 @@ function updateWithDataLoadError(state, action) { } if ( + checkRequestToken && dataRequest.dataRequestToken && dataRequest.dataRequestToken !== action.requestToken ) { // ignore responses to outdated requests - return state; + return; } - - dataRequest.dataHasLoadError = true; - dataRequest.dataLoadError = action.errorMessage; - dataRequest.dataRequestToken = null; - dataRequest.dataId = action.dataId; - const layerList = [...state.layerList]; - return { ...state, layerList }; + return dataRequest; } function findLayerById(state, id) { From b4c16cef26694d7d92693b04eaca64f206478bdb Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 12:42:21 -0700 Subject: [PATCH 11/17] Update tile sync function to more reliably confirm load status after loading via callback. Add interval to cancel timer --- .../gis/public/shared/layers/tile_layer.js | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index 55d188377850f..c485df26d72be 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -34,13 +34,32 @@ export class TileLayer extends ALayer { } _tileLoadErrorTracker(map, url) { - let tileLoadCount = 0; - map.on('tileload', ({ tile }) => tile && tileLoadCount++); + let tileLoad; + map.on('dataloading', ({ tile }) => { + if (tile && tile.request) { + // If at least one tile loads, endpoint/resource is valid + tile.request.onloadend = ({ loaded }) => loaded && (tileLoad = true); + } + }); return new Promise((resolve, reject) => { - const tileLoadTimer = setTimeout(() => { - map.off('sourcedata'); - if (!tileLoadCount) { + let tileLoadTimer = null; + let checkInterval = null; + + const clearChecks = () => { + clearInterval(checkInterval); + clearTimeout(tileLoadTimer); + map.off('dataloading'); + }; + + checkInterval = setInterval(() => { + if (tileLoad) { + resolve(); + clearChecks(); + } + }, 1000); + tileLoadTimer = setTimeout(() => { + if (!tileLoad) { try { throw new Error(`Tiles from "${url}" could not be loaded`); } catch (e) { @@ -49,11 +68,8 @@ export class TileLayer extends ALayer { } else { resolve(); } + clearChecks(); }, this.TMS_LOAD_TIMEOUT); - if (tileLoadCount) { - clearTimeout(tileLoadTimer); - resolve(); - } }); } From 76b357c4a61eb85fc51fcd789dffe9b1efffd5b6 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 13:13:10 -0700 Subject: [PATCH 12/17] Remove unnecessary, and annoying, clear temp layers on tms error --- x-pack/plugins/gis/public/actions/store_actions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/gis/public/actions/store_actions.js b/x-pack/plugins/gis/public/actions/store_actions.js index 3d1c9fe6dff99..34fb196aa7df4 100644 --- a/x-pack/plugins/gis/public/actions/store_actions.js +++ b/x-pack/plugins/gis/public/actions/store_actions.js @@ -112,7 +112,6 @@ export function addLayer(layerDescriptor) { export function setTmsErrorStatus(id, errorMessage) { return dispatch => { - dispatch(clearTemporaryLayers()); dispatch({ type: SET_TMS_ERROR_STATUS, layerId: id, From eca78ef71abd29b444c76438ab24b5664aacd683 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 13:52:59 -0700 Subject: [PATCH 13/17] Clean up --- .../plugins/gis/public/shared/layers/util/data_request.js | 8 -------- x-pack/plugins/gis/public/store/map.js | 4 +--- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/util/data_request.js b/x-pack/plugins/gis/public/shared/layers/util/data_request.js index 8079e0669853d..5abc2f7d088a7 100644 --- a/x-pack/plugins/gis/public/shared/layers/util/data_request.js +++ b/x-pack/plugins/gis/public/shared/layers/util/data_request.js @@ -9,14 +9,6 @@ export class DataRequest { this._descriptor = descriptor; } - hasLoadError() { - return this._descriptor.dataHasLoadError; - } - - getLoadError() { - return this._descriptor.dataLoadError; - } - getData() { return this._descriptor.data; } diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js index 3ff4017096ac4..518340c36bbcd 100644 --- a/x-pack/plugins/gis/public/store/map.js +++ b/x-pack/plugins/gis/public/store/map.js @@ -307,8 +307,6 @@ function updateWithDataRequest(state, action) { }; layerRequestingData.dataRequests.push(dataRequest); } - dataRequest.dataHasLoadError = false; - dataRequest.dataLoadError = null; dataRequest.dataMetaAtStart = action.meta; dataRequest.dataRequestToken = action.requestToken; const layerList = [...state.layerList]; @@ -343,7 +341,7 @@ function getValidDataRequest(state, action, checkRequestToken = true) { const dataRequest = findDataRequest(layer, action); if (!dataRequest) { - throw new Error('Data request should be initialized. Cannot call loadError before startLoading'); + return; } if ( From 7b752492de176382f5e15593ba9fc159f6144587 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 17 Jan 2019 15:23:40 -0700 Subject: [PATCH 14/17] More clean up --- x-pack/plugins/gis/public/shared/layers/layer.js | 2 +- x-pack/plugins/gis/public/store/map.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index 3685f4f0e7676..c5245c4611ee8 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -152,7 +152,7 @@ export class ALayer { } dataHasLoadError() { - return this._descriptor.errorState; + return this._descriptor && this._descriptor.errorState || false; } getDataLoadError() { diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js index 518340c36bbcd..d37bb53566c34 100644 --- a/x-pack/plugins/gis/public/store/map.js +++ b/x-pack/plugins/gis/public/store/map.js @@ -138,8 +138,8 @@ export function map(state = INITIAL_STATE, action) { case SET_TMS_ERROR_STATUS: return setErrorStatus(state, action); case LAYER_DATA_LOAD_ERROR: - return resetDataRequest( - setErrorStatus(state, action), action); + const errorRequestResetState = resetDataRequest(state, action); + return setErrorStatus(errorRequestResetState, action); case LAYER_DATA_LOAD_ENDED: return updateWithDataResponse(state, action); case TOUCH_LAYER: @@ -305,7 +305,9 @@ function updateWithDataRequest(state, action) { dataRequest = { dataId: action.dataId }; - layerRequestingData.dataRequests.push(dataRequest); + layerRequestingData.dataRequests = [ + ...(layerRequestingData.dataRequests + ? layerRequestingData.dataRequests : []), dataRequest ]; } dataRequest.dataMetaAtStart = action.meta; dataRequest.dataRequestToken = action.requestToken; From adf49622df9c3b23fd13ef3d1efc352d11e4e9f9 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Thu, 24 Jan 2019 13:19:31 -0700 Subject: [PATCH 15/17] Review feedback --- x-pack/plugins/gis/public/actions/store_actions.js | 6 +++--- .../plugins/gis/public/components/map/mb/index.js | 6 +++--- .../plugins/gis/public/components/map/mb/view.js | 14 +++----------- .../layer_control/layer_toc/toc_entry/toc_entry.js | 7 ++++--- x-pack/plugins/gis/public/shared/layers/layer.js | 14 +++++--------- .../sources/ems_tms_source/ems_tms_source.js | 3 +-- .../plugins/gis/public/shared/layers/tile_layer.js | 14 +------------- x-pack/plugins/gis/public/store/map.js | 6 +++--- 8 files changed, 23 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/gis/public/actions/store_actions.js b/x-pack/plugins/gis/public/actions/store_actions.js index 09dd36038b29e..f83d455c98bbf 100644 --- a/x-pack/plugins/gis/public/actions/store_actions.js +++ b/x-pack/plugins/gis/public/actions/store_actions.js @@ -21,7 +21,7 @@ import { timeService } from '../kibana_services'; export const SET_SELECTED_LAYER = 'SET_SELECTED_LAYER'; export const UPDATE_LAYER_ORDER = 'UPDATE_LAYER_ORDER'; export const ADD_LAYER = 'ADD_LAYER'; -export const SET_TMS_ERROR_STATUS = 'SET_TMS_ERROR_STATUS'; +export const SET_LAYER_ERROR_STATUS = 'SET_LAYER_ERROR_STATUS'; export const ADD_WAITING_FOR_MAP_READY_LAYER = 'ADD_WAITING_FOR_MAP_READY_LAYER'; export const CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST = 'CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST'; export const REMOVE_LAYER = 'REMOVE_LAYER'; @@ -109,10 +109,10 @@ export function addLayer(layerDescriptor) { }; } -export function setTmsErrorStatus(id, errorMessage) { +export function setLayerErrorStatus(id, errorMessage) { return dispatch => { dispatch({ - type: SET_TMS_ERROR_STATUS, + type: SET_LAYER_ERROR_STATUS, layerId: id, errorMessage, }); diff --git a/x-pack/plugins/gis/public/components/map/mb/index.js b/x-pack/plugins/gis/public/components/map/mb/index.js index 65416f17606c1..be7f44ba1908a 100644 --- a/x-pack/plugins/gis/public/components/map/mb/index.js +++ b/x-pack/plugins/gis/public/components/map/mb/index.js @@ -13,7 +13,7 @@ import { setMouseCoordinates, clearMouseCoordinates, clearGoto, - setTmsErrorStatus, + setLayerErrorStatus, } from '../../../actions/store_actions'; import { getLayerList, getMapReady, getGoto } from "../../../selectors/map_selectors"; @@ -47,8 +47,8 @@ function mapDispatchToProps(dispatch) { clearGoto: () => { dispatch(clearGoto()); }, - setTmsErrorStatus: (id, msg) => - dispatch(setTmsErrorStatus(id, msg)) + setLayerErrorStatus: (id, msg) => + dispatch(setLayerErrorStatus(id, msg)) }; } diff --git a/x-pack/plugins/gis/public/components/map/mb/view.js b/x-pack/plugins/gis/public/components/map/mb/view.js index d7639bdaa7810..02c86a52a902c 100644 --- a/x-pack/plugins/gis/public/components/map/mb/view.js +++ b/x-pack/plugins/gis/public/components/map/mb/view.js @@ -188,18 +188,10 @@ export class MBMapContainer extends React.Component { removeOrphanedSourcesAndLayers(this._mbMap, layerList); layerList.forEach(layer => { - if (!layer.dataHasLoadError()) { + if (!layer.hasErrors()) { Promise.resolve(layer.syncLayerWithMB(this._mbMap)) - .catch(({ message }) => { - switch(layer._descriptor.type) { - case 'TILE': - console.warn(`Sync error retrieving tiles from TMS: ${message}`); - this.props.setTmsErrorStatus(layer.getId(), message); - break; - default: - console.warn(`Layer sync error: ${message}`); - } - }); + .catch(({ message }) => + this.props.setLayerErrorStatus(layer.getId(), message)); } }); syncLayerOrder(this._mbMap, layerList); diff --git a/x-pack/plugins/gis/public/components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry.js b/x-pack/plugins/gis/public/components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry.js index 3789ad2c0df9f..8fae7835272e3 100644 --- a/x-pack/plugins/gis/public/components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry.js +++ b/x-pack/plugins/gis/public/components/widget_overlay/layer_control/layer_toc/toc_entry/toc_entry.js @@ -62,14 +62,14 @@ export class TOCEntry extends React.Component { }); let visibilityIndicator; - if (layer.dataHasLoadError()) { + if (layer.hasErrors()) { visibilityIndicator = ( ); } else if (layer.isLayerLoading()) { @@ -110,7 +110,8 @@ export class TOCEntry extends React.Component { alignItems="center" responsive={false} className={ - layer.isVisible() && layer.showAtZoomLevel(zoom) && !layer.dataHasLoadError() ? 'gisTocEntry-visible' : 'gisTocEntry-notVisible' + layer.isVisible() && layer.showAtZoomLevel(zoom) + && !layer.hasErrors() ? 'gisTocEntry-visible' : 'gisTocEntry-notVisible' } > diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index 1ec6ec8f23cc6..64d20321399e7 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -64,7 +64,7 @@ export class ALayer { } async getAttributions() { - if (!this.dataHasLoadError()) { + if (!this.hasErrors()) { return await this._source.getAttributions(); } return ''; @@ -142,10 +142,6 @@ export class ALayer { return this._source.renderSourceSettingsEditor({ onChange }); }; - _findDataRequestForSource(sourceDataId) { - return this._dataRequests.find(dataRequest => dataRequest.getDataId() === sourceDataId); - } - getSourceDataRequest() { return this._dataRequests.find(dataRequest => dataRequest.getDataId() === 'source'); } @@ -154,12 +150,12 @@ export class ALayer { return this._dataRequests.some(dataRequest => dataRequest.isLoading()); } - dataHasLoadError() { - return this._descriptor && this._descriptor.errorState || false; + hasErrors() { + return _.get(this._descriptor, 'isInErrorState', false); } - getDataLoadError() { - return this.dataHasLoadError() ? this._descriptor.errorMessage : ''; + getErrors() { + return this.hasErrors() ? this._descriptor.errorMessage : ''; } toLayerDescriptor() { diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js index 34cfda7bd2c52..da411202d701e 100644 --- a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js @@ -79,7 +79,6 @@ export class EMSTMSSource extends TMSSource { return service.id === this._descriptor.id; }); if (!emsTmsService) { - console.error(`EMS TMS Service: ${this._descriptor.id} currently unavailable`); return; } return emsTmsService; @@ -108,7 +107,7 @@ export class EMSTMSSource extends TMSSource { let attributions; try { service = this._getTMSOptions(); - attributions = service.attributionMarkdown.split('|'); + attributions = service && service.attributionMarkdown.split('|'); } catch (e) { console.warn(`Error obtaining attributions: ${e}`); } diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index 62259bd05a9b5..e121d8e744837 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -42,27 +42,15 @@ export class TileLayer extends ALayer { return new Promise((resolve, reject) => { let tileLoadTimer = null; - let checkInterval = null; const clearChecks = () => { - clearInterval(checkInterval); clearTimeout(tileLoadTimer); map.off('dataloading'); }; - checkInterval = setInterval(() => { - if (tileLoad) { - resolve(); - clearChecks(); - } - }, 1000); tileLoadTimer = setTimeout(() => { if (!tileLoad) { - try { - throw new Error(`Tiles from "${url}" could not be loaded`); - } catch (e) { - reject(e); - } + reject(new Error(`Tiles from "${url}" could not be loaded`)); } else { resolve(); } diff --git a/x-pack/plugins/gis/public/store/map.js b/x-pack/plugins/gis/public/store/map.js index e8ddc91e9b021..8c7f4ac79ef4c 100644 --- a/x-pack/plugins/gis/public/store/map.js +++ b/x-pack/plugins/gis/public/store/map.js @@ -11,7 +11,7 @@ import { LAYER_DATA_LOAD_ENDED, LAYER_DATA_LOAD_ERROR, ADD_LAYER, - SET_TMS_ERROR_STATUS, + SET_LAYER_ERROR_STATUS, ADD_WAITING_FOR_MAP_READY_LAYER, CLEAR_WAITING_FOR_MAP_READY_LAYER_LIST, REMOVE_LAYER, @@ -134,7 +134,7 @@ export function map(state = INITIAL_STATE, action) { }; case LAYER_DATA_LOAD_STARTED: return updateWithDataRequest(state, action); - case SET_TMS_ERROR_STATUS: + case SET_LAYER_ERROR_STATUS: return setErrorStatus(state, action); case LAYER_DATA_LOAD_ERROR: const errorRequestResetState = resetDataRequest(state, action); @@ -272,7 +272,7 @@ function setErrorStatus(state, { layerId, errorMessage }) { const tmsErrorLayer = state.layerList.find(({ id }) => id === layerId); return tmsErrorLayer ? updateLayerInList( - updateLayerInList(state, tmsErrorLayer.id, 'errorState', true), + updateLayerInList(state, tmsErrorLayer.id, 'isInErrorState', true), tmsErrorLayer.id, 'errorMessage', errorMessage) : state; } From 0a205a32b7810fffe4385f6b5018d041d033b0a9 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Fri, 25 Jan 2019 10:27:48 -0700 Subject: [PATCH 16/17] Review feedback. Test cleanup --- .../plugins/gis/public/shared/layers/layer.js | 2 +- .../sources/ems_tms_source/ems_tms_source.js | 41 ++++++++----------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index 64d20321399e7..c3d442fdc9d6f 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -32,7 +32,7 @@ export class ALayer { static createDescriptor(options = {}) { const layerDescriptor = { ...options }; - layerDescriptor.type = undefined; + layerDescriptor.source = this._source; layerDescriptor.dataRequests = _.get(options, 'dataRequests', []); layerDescriptor.id = _.get(options, 'id', Math.random().toString(36).substr(2, 5)); layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null; diff --git a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js index da411202d701e..4644bd3de166f 100644 --- a/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js +++ b/x-pack/plugins/gis/public/shared/layers/sources/ems_tms_source/ems_tms_source.js @@ -71,17 +71,13 @@ export class EMSTMSSource extends TMSSource { } _getTMSOptions() { - if(!this._emsTileServices || !this._emsTileServices.length) { + if(!this._emsTileServices) { return; } - const emsTmsService = this._emsTileServices.find(service => { + return this._emsTileServices.find(service => { return service.id === this._descriptor.id; }); - if (!emsTmsService) { - return; - } - return emsTmsService; } _createDefaultLayerDescriptor(options) { @@ -103,26 +99,21 @@ export class EMSTMSSource extends TMSSource { } async getAttributions() { - let service; - let attributions; - try { - service = this._getTMSOptions(); - attributions = service && service.attributionMarkdown.split('|'); - } catch (e) { - console.warn(`Error obtaining attributions: ${e}`); + const service = this._getTMSOptions(); + if (!service || !service.attributionMarkdown) { + return []; } - return attributions - ? attributions.map((attribution) => { - attribution = attribution.trim(); - //this assumes attribution is plain markdown link - const extractLink = /\[(.*)\]\((.*)\)/; - const result = extractLink.exec(attribution); - return { - label: result ? result[1] : null, - url: result ? result[2] : null - }; - }) - : ''; + + return service.attributionMarkdown.split('|').map((attribution) => { + attribution = attribution.trim(); + //this assumes attribution is plain markdown link + const extractLink = /\[(.*)\]\((.*)\)/; + const result = extractLink.exec(attribution); + return { + label: result ? result[1] : null, + url: result ? result[2] : null + }; + }); } getUrlTemplate() { From 14e94cb4efdb700347aee85ae316f02f1a3e4601 Mon Sep 17 00:00:00 2001 From: Aaron Caldwell Date: Mon, 28 Jan 2019 09:10:05 -0700 Subject: [PATCH 17/17] Test fixes and review feedback --- .../shared/components/layer_toc_actions.js | 4 +- .../plugins/gis/public/shared/layers/layer.js | 3 +- .../gis/public/shared/layers/tile_layer.js | 70 +++++++++---------- 3 files changed, 35 insertions(+), 42 deletions(-) diff --git a/x-pack/plugins/gis/public/shared/components/layer_toc_actions.js b/x-pack/plugins/gis/public/shared/components/layer_toc_actions.js index da07fbfc335c9..7fa88e1b9da25 100644 --- a/x-pack/plugins/gis/public/shared/components/layer_toc_actions.js +++ b/x-pack/plugins/gis/public/shared/components/layer_toc_actions.js @@ -77,14 +77,14 @@ export class LayerTocActions extends Component { _renderIcon() { const { zoom, layer } = this.props; let smallLegendIcon; - if (layer.dataHasLoadError()) { + if (layer.hasErrors()) { smallLegendIcon = ( ); } else if (layer.isLayerLoading()) { diff --git a/x-pack/plugins/gis/public/shared/layers/layer.js b/x-pack/plugins/gis/public/shared/layers/layer.js index e552da1dab2a8..ab6c5ef5345e2 100644 --- a/x-pack/plugins/gis/public/shared/layers/layer.js +++ b/x-pack/plugins/gis/public/shared/layers/layer.js @@ -32,7 +32,6 @@ export class AbstractLayer { static createDescriptor(options = {}) { const layerDescriptor = { ...options }; - layerDescriptor.source = this._source; layerDescriptor.dataRequests = _.get(options, 'dataRequests', []); layerDescriptor.id = _.get(options, 'id', Math.random().toString(36).substr(2, 5)); layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null; @@ -67,7 +66,7 @@ export class AbstractLayer { if (!this.hasErrors()) { return await this._source.getAttributions(); } - return ''; + return []; } getLabel() { diff --git a/x-pack/plugins/gis/public/shared/layers/tile_layer.js b/x-pack/plugins/gis/public/shared/layers/tile_layer.js index 08978a8069e5b..75e42d8123025 100644 --- a/x-pack/plugins/gis/public/shared/layers/tile_layer.js +++ b/x-pack/plugins/gis/public/shared/layers/tile_layer.js @@ -10,10 +10,11 @@ import React from 'react'; import { EuiIcon } from '@elastic/eui'; import { TileStyle } from '../layers/styles/tile_style'; +const TMS_LOAD_TIMEOUT = 32000; + export class TileLayer extends AbstractLayer { static type = "TILE"; - TMS_LOAD_TIMEOUT = 32000; constructor({ layerDescriptor, source, style }) { super({ layerDescriptor, source, style }); @@ -36,7 +37,11 @@ export class TileLayer extends AbstractLayer { map.on('dataloading', ({ tile }) => { if (tile && tile.request) { // If at least one tile loads, endpoint/resource is valid - tile.request.onloadend = ({ loaded }) => loaded && (tileLoad = true); + tile.request.onloadend = ({ loaded }) => { + if (loaded) { + tileLoad = true; + } + }; } }); @@ -55,7 +60,7 @@ export class TileLayer extends AbstractLayer { resolve(); } clearChecks(); - }, this.TMS_LOAD_TIMEOUT); + }, TMS_LOAD_TIMEOUT); }); } @@ -67,42 +72,31 @@ export class TileLayer extends AbstractLayer { return; } - let url; - return new Promise((resolve, reject) => { - try { - url = this._source.getUrlTemplate(); - } catch (e) { - reject(e); - } + const url = this._source.getUrlTemplate(); + const sourceId = this.getId(); + mbMap.addSource(sourceId, { + type: 'raster', + tiles: [url], + tileSize: 256, + scheme: 'xyz', + }); + + mbMap.addLayer({ + id: layerId, + type: 'raster', + source: sourceId, + minzoom: 0, + maxzoom: 22, + }); + + await this._tileLoadErrorTracker(mbMap, url); - const sourceId = this.getId(); - mbMap.addSource(sourceId, { - type: 'raster', - tiles: [url], - tileSize: 256, - scheme: 'xyz', - }); - - mbMap.addLayer({ - id: layerId, - type: 'raster', - source: sourceId, - minzoom: 0, - maxzoom: 22, - }); - resolve(); - }).then(() => this._tileLoadErrorTracker(mbMap, url) - ).then(() => { - mbMap.setLayoutProperty(layerId, 'visibility', this.isVisible() - ? 'visible' - : 'none'); - mbMap.setLayerZoomRange(layerId, this._descriptor.minZoom, - this._descriptor.maxZoom); - this._style && this._style.setMBPaintProperties({ - alpha: this.getAlpha(), - mbMap, - layerId, - }); + mbMap.setLayoutProperty(layerId, 'visibility', this.isVisible() ? 'visible' : 'none'); + mbMap.setLayerZoomRange(layerId, this._descriptor.minZoom, this._descriptor.maxZoom); + this._style && this._style.setMBPaintProperties({ + alpha: this.getAlpha(), + mbMap, + layerId, }); }