"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.autoFitToBounds = autoFitToBounds; exports.cancelAllInFlightRequests = cancelAllInFlightRequests; exports.clearDataRequests = clearDataRequests; exports.fitToDataBounds = fitToDataBounds; exports.fitToLayerExtent = fitToLayerExtent; exports.setLayerDataLoadErrorStatus = setLayerDataLoadErrorStatus; exports.syncDataForAllLayers = syncDataForAllLayers; exports.syncDataForLayer = syncDataForLayer; exports.syncDataForLayerDueToDrawing = syncDataForLayerDueToDrawing; exports.syncDataForLayerId = syncDataForLayerId; exports.updateSourceDataRequest = updateSourceDataRequest; exports.updateStyleMeta = updateStyleMeta; var _uuid = require("uuid"); var _constants = require("../../common/constants"); var _map_selectors = require("../selectors/map_selectors"); var _non_serializable_instances = require("../reducers/non_serializable_instances"); var _map_action_constants = require("./map_action_constants"); var _data_request = require("../classes/util/data_request"); var _elasticsearch_util = require("../../common/elasticsearch_util"); var _get_layers_extent = require("./get_layers_extent"); var _layer_group = require("../classes/layers/layer_group"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ const FIT_TO_BOUNDS_SCALE_FACTOR = 0.1; function clearDataRequests(layer) { return dispatch => { layer.getInFlightRequestTokens().forEach(requestToken => { dispatch((0, _non_serializable_instances.cancelRequest)(requestToken)); }); dispatch({ type: _map_action_constants.UPDATE_LAYER_PROP, id: layer.getId(), propName: '__dataRequests', newValue: [] }); }; } function cancelAllInFlightRequests() { return (dispatch, getState) => { (0, _map_selectors.getLayerList)(getState()).forEach(layer => { dispatch(clearDataRequests(layer)); }); }; } function updateStyleMeta(layerId) { return async (dispatch, getState) => { const layer = (0, _map_selectors.getLayerById)(layerId, getState()); if (!layer || (0, _layer_group.isLayerGroup)(layer)) { return; } const styleMeta = await layer.getStyleMetaDescriptorFromLocalFeatures(); if (!styleMeta) { return; } dispatch({ type: _map_action_constants.SET_LAYER_STYLE_META, layerId, styleMeta }); }; } function getDataRequestContext(dispatch, getState, layerId, forceRefreshDueToDrawing, isForceRefresh) { var _getEditState; return { dataFilters: (0, _map_selectors.getDataFilters)(getState()), startLoading: (dataId, requestToken, meta) => dispatch(startDataLoad(layerId, dataId, requestToken, meta)), stopLoading: (dataId, requestToken, data, meta) => dispatch(endDataLoad(layerId, dataId, requestToken, data, meta)), onLoadError: (dataId, requestToken, errorMessage) => dispatch(onDataLoadError(layerId, dataId, requestToken, errorMessage)), onJoinError: errorMessage => dispatch(setLayerDataLoadErrorStatus(layerId, errorMessage)), updateSourceData: newData => { dispatch(updateSourceDataRequest(layerId, newData)); }, isRequestStillActive: (dataId, requestToken) => { const dataRequest = (0, _map_selectors.getDataRequestDescriptor)(getState(), layerId, dataId); if (!dataRequest) { return false; } return dataRequest.dataRequestToken === requestToken; }, registerCancelCallback: (requestToken, callback) => dispatch((0, _non_serializable_instances.registerCancelCallback)(requestToken, callback)), forceRefreshDueToDrawing, isForceRefresh, isFeatureEditorOpenForLayer: ((_getEditState = (0, _map_selectors.getEditState)(getState())) === null || _getEditState === void 0 ? void 0 : _getEditState.layerId) === layerId, inspectorAdapters: (0, _non_serializable_instances.getInspectorAdapters)(getState()) }; } function syncDataForAllLayers(isForceRefresh) { return async (dispatch, getState) => { const syncPromises = (0, _map_selectors.getLayerList)(getState()).map(layer => { return dispatch(syncDataForLayer(layer, isForceRefresh)); }); await Promise.all(syncPromises); }; } function syncDataForAllJoinLayers() { return async (dispatch, getState) => { const syncPromises = (0, _map_selectors.getLayerList)(getState()).filter(layer => { return 'hasJoins' in layer ? layer.hasJoins() : false; }).map(layer => { return dispatch(syncDataForLayer(layer, false)); }); await Promise.all(syncPromises); }; } function syncDataForLayerDueToDrawing(layer) { return async (dispatch, getState) => { const dataRequestContext = getDataRequestContext(dispatch, getState, layer.getId(), true, false); if (!layer.isVisible() || !layer.showAtZoomLevel(dataRequestContext.dataFilters.zoom)) { return; } await layer.syncData(dataRequestContext); }; } function syncDataForLayer(layer, isForceRefresh) { return async (dispatch, getState) => { const dataRequestContext = getDataRequestContext(dispatch, getState, layer.getId(), false, isForceRefresh); if (!layer.isVisible() || !layer.showAtZoomLevel(dataRequestContext.dataFilters.zoom)) { return; } await layer.syncData(dataRequestContext); }; } function syncDataForLayerId(layerId, isForceRefresh) { return async (dispatch, getState) => { const layer = (0, _map_selectors.getLayerById)(layerId, getState()); if (layer) { dispatch(syncDataForLayer(layer, isForceRefresh)); } }; } function setLayerDataLoadErrorStatus(layerId, errorMessage) { return { type: _map_action_constants.SET_LAYER_ERROR_STATUS, isInErrorState: errorMessage !== null, layerId, errorMessage }; } function startDataLoad(layerId, dataId, requestToken, meta) { return (dispatch, getState) => { const layer = (0, _map_selectors.getLayerById)(layerId, getState()); if (layer) { dispatch((0, _non_serializable_instances.cancelRequest)(layer.getPrevRequestToken(dataId))); } const eventHandlers = (0, _non_serializable_instances.getEventHandlers)(getState()); if (eventHandlers && eventHandlers.onDataLoad) { eventHandlers.onDataLoad({ layerId, dataId }); } dispatch({ meta, type: _map_action_constants.LAYER_DATA_LOAD_STARTED, layerId, dataId, requestToken }); }; } function endDataLoad(layerId, dataId, requestToken, data, meta) { return (dispatch, getState) => { dispatch((0, _non_serializable_instances.unregisterCancelCallback)(requestToken)); const dataRequest = (0, _map_selectors.getDataRequestDescriptor)(getState(), layerId, dataId); if (dataRequest && dataRequest.dataRequestToken !== requestToken) { // todo - investigate - this may arise with failing style meta request and should not throw in that case throw new _data_request.DataRequestAbortError(); } const features = data && 'features' in data ? data.features : []; const layer = (0, _map_selectors.getLayerById)(layerId, getState()); const eventHandlers = (0, _non_serializable_instances.getEventHandlers)(getState()); if (eventHandlers && eventHandlers.onDataLoadEnd) { const resultMeta = {}; if (layer && layer.getType() === _constants.LAYER_TYPE.GEOJSON_VECTOR) { const featuresWithoutCentroids = features.filter(feature => { return feature.properties ? !feature.properties[_constants.KBN_IS_CENTROID_FEATURE] : true; }); resultMeta.featuresCount = featuresWithoutCentroids.length; } eventHandlers.onDataLoadEnd({ layerId, dataId, resultMeta }); } dispatch({ type: _map_action_constants.LAYER_DATA_LOAD_ENDED, layerId, dataId, data, meta, requestToken }); // Clear any data-load errors when there is a succesful data return. // Co this on end-data-load iso at start-data-load to avoid blipping the error status between true/false. // This avoids jitter in the warning icon of the TOC when the requests continues to return errors. dispatch(setLayerDataLoadErrorStatus(layerId, null)); dispatch(updateStyleMeta(layerId)); }; } function onDataLoadError(layerId, dataId, requestToken, errorMessage) { return async (dispatch, getState) => { dispatch((0, _non_serializable_instances.unregisterCancelCallback)(requestToken)); const eventHandlers = (0, _non_serializable_instances.getEventHandlers)(getState()); if (eventHandlers && eventHandlers.onDataLoadError) { eventHandlers.onDataLoadError({ layerId, dataId, errorMessage }); } dispatch({ type: _map_action_constants.LAYER_DATA_LOAD_ERROR, layerId, dataId, requestToken }); dispatch(setLayerDataLoadErrorStatus(layerId, errorMessage)); }; } function updateSourceDataRequest(layerId, newData) { return (dispatch, getState) => { dispatch({ type: _map_action_constants.UPDATE_SOURCE_DATA_REQUEST, dataId: _constants.SOURCE_DATA_REQUEST_ID, layerId, newData }); dispatch(updateStyleMeta(layerId)); }; } function fitToLayerExtent(layerId) { return async (dispatch, getState) => { const targetLayer = (0, _map_selectors.getLayerById)(layerId, getState()); if (targetLayer) { try { const bounds = await targetLayer.getBounds(boundsLayerId => getDataRequestContext(dispatch, getState, boundsLayerId, false, false)); if (bounds) { await dispatch(setGotoWithBounds((0, _elasticsearch_util.scaleBounds)(bounds, FIT_TO_BOUNDS_SCALE_FACTOR))); } } catch (error) { if (!(error instanceof _data_request.DataRequestAbortError)) { // eslint-disable-next-line no-console console.warn('Unhandled getBounds error for layer. Only DataRequestAbortError should be surfaced', error); } // new fitToLayerExtent request has superseded this thread of execution. Results no longer needed. return; } } }; } function fitToDataBounds(onNoBounds) { return async (dispatch, getState) => { const rootLayers = (0, _map_selectors.getLayerList)(getState()).filter(layer => { return layer.getParent() === undefined; }); const extent = await (0, _get_layers_extent.getLayersExtent)(rootLayers, boundsLayerId => getDataRequestContext(dispatch, getState, boundsLayerId, false, false)); if (extent === null) { if (onNoBounds) { onNoBounds(); } return; } dispatch(setGotoWithBounds((0, _elasticsearch_util.scaleBounds)(extent, FIT_TO_BOUNDS_SCALE_FACTOR))); }; } let lastSetQueryCallId = ''; function autoFitToBounds() { return async dispatch => { // Method can be triggered before async actions complete // Use localSetQueryCallId to only continue execution path if method has not been re-triggered. const localSetQueryCallId = (0, _uuid.v4)(); lastSetQueryCallId = localSetQueryCallId; // Joins are performed on the client. // As a result, bounds for join layers must also be performed on the client. // Therefore join layers need to fetch data prior to auto fitting bounds. await dispatch(syncDataForAllJoinLayers()); if (localSetQueryCallId === lastSetQueryCallId) { // In cases where there are no bounds, such as no matching documents, fitToDataBounds does not trigger setGotoWithBounds. // Ensure layer syncing occurs when setGotoWithBounds is not triggered. function onNoBounds() { if (localSetQueryCallId === lastSetQueryCallId) { dispatch(syncDataForAllLayers(false)); } } dispatch(fitToDataBounds(onNoBounds)); } }; } function setGotoWithBounds(bounds) { return { type: _map_action_constants.SET_GOTO, bounds }; }