import { createSelector } from 'reselect' ; import { FeatureCollection } from 'geojson' ; import _ from 'lodash' ; import { Adapters } from 'src/plugins/inspector/public' ; import type { Query } from 'src/plugins/data/common' ; import { Filter } from '@kbn/es-query' ; import { RasterTileLayer } from '../classes/layers/raster_tile_layer/raster_tile_layer' ; import { EmsVectorTileLayer } from '../classes/layers/ems_vector_tile_layer/ems_vector_tile_layer' ; import { BlendedVectorLayer , IVectorLayer , MvtVectorLayer , GeoJsonVectorLayer , } from '../classes/layers/vector_layer' ; import { VectorStyle } from '../classes/styles/vector/vector_style' ; import { HeatmapLayer } from '../classes/layers/heatmap_layer' ; import { getTimeFilter } from '../kibana_services' ; import { getChartsPaletteServiceGetColor , getInspectorAdapters , } from '../reducers/non_serializable_instances' ; import { copyPersistentState , TRACKED_LAYER_DESCRIPTOR } from '../reducers/copy_persistent_state' ; import { InnerJoin } from '../classes/joins/inner_join' ; import { getSourceByType } from '../classes/sources/source_registry' ; import { GeoJsonFileSource } from '../classes/sources/geojson_file_source' ; import { LAYER_TYPE , SOURCE_DATA_REQUEST_ID , SPATIAL_FILTERS_LAYER_ID , STYLE_TYPE , VECTOR_STYLES , } from '../../common/constants' ; import { extractFeaturesFromFilters } from '../../common/elasticsearch_util' ; import { MapStoreState } from '../reducers/store' ; import { AbstractSourceDescriptor , DataRequestDescriptor , DrawState , EditState , Goto , HeatmapLayerDescriptor , LayerDescriptor , MapCenter , MapExtent , TooltipState , VectorLayerDescriptor , } from '../../common/descriptor_types' ; import { MapSettings } from '../reducers/map' ; import { TimeRange } from '../../../../../src/plugins/data/public' ; import { ISource } from '../classes/sources/source' ; import { ITMSSource } from '../classes/sources/tms_source' ; import { IVectorSource } from '../classes/sources/vector_source' ; import { ESGeoGridSource } from '../classes/sources/es_geo_grid_source' ; import { EMSTMSSource } from '../classes/sources/ems_tms_source' ; import { ILayer } from '../classes/layers/layer' ; import { getIsReadOnly } from './ui_selectors' ; export function createLayerInstance ( layerDescriptor , inspectorAdapters ? , chartsPaletteServiceGetColor ? ) { const source = createSourceInstance ( layerDescriptor . sourceDescriptor , inspectorAdapters ) ; switch ( layerDescriptor . type ) { case LAYER_TYPE . RASTER_TILE : return new RasterTileLayer ( { layerDescriptor , source : source as ITMSSource } ) ; case LAYER_TYPE . GEOJSON_VECTOR : const joins = [ ] ; const vectorLayerDescriptor = layerDescriptor as VectorLayerDescriptor ; if ( vectorLayerDescriptor . joins ) { vectorLayerDescriptor . joins . forEach ( ( joinDescriptor ) => { const join = new InnerJoin ( joinDescriptor , source as IVectorSource ) ; joins . push ( join ) ; } ) ; } return new GeoJsonVectorLayer ( { layerDescriptor : vectorLayerDescriptor , source : source as IVectorSource , joins , chartsPaletteServiceGetColor , } ) ; case LAYER_TYPE . EMS_VECTOR_TILE : return new EmsVectorTileLayer ( { layerDescriptor , source : source as EMSTMSSource } ) ; case LAYER_TYPE . HEATMAP : return new HeatmapLayer ( { layerDescriptor : layerDescriptor as HeatmapLayerDescriptor , source : source as ESGeoGridSource , } ) ; case LAYER_TYPE . BLENDED_VECTOR : return new BlendedVectorLayer ( { layerDescriptor : layerDescriptor as VectorLayerDescriptor , source : source as IVectorSource , chartsPaletteServiceGetColor , } ) ; case LAYER_TYPE . MVT_VECTOR : return new MvtVectorLayer ( { layerDescriptor : layerDescriptor as VectorLayerDescriptor , source : source as IVectorSource , } ) ; default : throw new Error ( `Unrecognized layerType ${ layerDescriptor . type }` ) ; } } function createSourceInstance ( sourceDescriptor , inspectorAdapters ? ) { if ( sourceDescriptor === null ) { throw new Error ( 'Source-descriptor should be initialized' ) ; } const source = getSourceByType ( sourceDescriptor . type ) ; if ( ! source ) { throw new Error ( `Unrecognized sourceType ${ sourceDescriptor . type }` ) ; } return new source . ConstructorFunction ( sourceDescriptor , inspectorAdapters ) ; } export const getMapSettings = ( { map } ) : MapSettings => map . settings ; const getRollbackMapSettings = ( { map } ) : MapSettings | null => map . __rollbackSettings ; export const hasMapSettingsChanges = createSelector ( getMapSettings , getRollbackMapSettings , ( settings , rollbackSettings ) => { return rollbackSettings ? ! _ . isEqual ( settings , rollbackSettings ) : false ; } ) ; export const getOpenTooltips = ( { map } ) : TooltipState [ ] => { return map && map . openTooltips ? map . openTooltips : [ ] ; } ; export const getHasLockedTooltips = ( state ) : boolean => { return getOpenTooltips ( state ) . some ( ( { isLocked } ) => { return isLocked ; } ) ; } ; export const getMapReady = ( { map } ) : boolean => map && map . ready ; export const getMapInitError = ( { map } ) : string | null | undefined => map . mapInitError ; export const getGoto = ( { map } ) : Goto | null | undefined => map && map . goto ; export const getSelectedLayerId = ( { map } ) : string | null => { return ! map . selectedLayerId || ! map . layerList ? null : map . selectedLayerId ; } ; export const getLayerListRaw = ( { map } ) : LayerDescriptor [ ] => map . layerList ? map . layerList : [ ] ; export const getWaitingForMapReadyLayerListRaw = ( { map } ) : LayerDescriptor [ ] => map . waitingForMapReadyLayerList ? map . waitingForMapReadyLayerList : [ ] ; export const getScrollZoom = ( { map } ) : boolean => map . mapState . scrollZoom ; export const getMapExtent = ( { map } ) : MapExtent | undefined => map . mapState . extent ; export const getMapBuffer = ( { map } ) : MapExtent | undefined => map . mapState . buffer ; export const getMapZoom = ( { map } ) : number => map . mapState . zoom ? map . mapState . zoom : 0 ; export const getMapCenter = ( { map } ) : MapCenter => map . mapState . center ? map . mapState . center : { lat : 0 , lon : 0 } ; export const getMouseCoordinates = ( { map } ) => map . mapState . mouseCoordinates ; export const getTimeFilters = ( { map } ) : TimeRange => map . mapState . timeFilters ? map . mapState . timeFilters : getTimeFilter ( ) . getTime ( ) ; export const getTimeslice = ( { map } ) => map . mapState . timeslice ; export const getQuery = ( { map } ) : Query | undefined => map . mapState . query ; export const getFilters = ( { map } ) : Filter [ ] => map . mapState . filters ; export const getSearchSessionId = ( { map } ) : string | undefined => map . mapState . searchSessionId ; export const getSearchSessionMapBuffer = ( { map } ) : MapExtent | undefined => map . mapState . searchSessionMapBuffer ; export const isUsingSearch = ( state ) : boolean => { const filters = getFilters ( state ) . filter ( ( filter ) => ! filter . meta . disabled ) ; const queryString = _ . get ( getQuery ( state ) , 'query' , '' ) ; return ! ! filters . length || ! ! queryString . length ; } ; export const getDrawState = ( { map } ) : DrawState | undefined => map . mapState . drawState ; export const getEditState = ( { map } ) : EditState | undefined => map . mapState . editState ; function getLayerDescriptor ( state , layerId ) { const layerListRaw = getLayerListRaw ( state ) ; return layerListRaw . find ( ( layer ) => layer . id === layerId ) ; } export function getDataRequestDescriptor ( state , layerId , dataId ) { const layerDescriptor = getLayerDescriptor ( state , layerId ) ; if ( ! layerDescriptor || ! layerDescriptor . __dataRequests ) { return ; } return layerDescriptor . __dataRequests . find ( ( dataRequest ) => { return dataRequest . dataId === dataId ; } ) ; } export const getDataFilters = createSelector ( getMapExtent , getMapBuffer , getMapZoom , getTimeFilters , getTimeslice , getQuery , getFilters , getSearchSessionId , getSearchSessionMapBuffer , getIsReadOnly , ( mapExtent , mapBuffer , mapZoom , timeFilters , timeslice , query , filters , searchSessionId , searchSessionMapBuffer , isReadOnly ) => { return { extent : mapExtent , buffer : searchSessionId && searchSessionMapBuffer ? searchSessionMapBuffer : mapBuffer , zoom : mapZoom , timeFilters , timeslice , query , filters , searchSessionId , isReadOnly , } ; } ) ; export const getSpatialFiltersLayer = createSelector ( getFilters , getMapSettings , ( filters , settings ) => { const featureCollection = { type : 'FeatureCollection' , features : extractFeaturesFromFilters ( filters ) , } ; const geoJsonSourceDescriptor = GeoJsonFileSource . createDescriptor ( { __featureCollection : featureCollection , name : 'spatialFilters' , } ) ; return new GeoJsonVectorLayer ( { layerDescriptor : GeoJsonVectorLayer . createDescriptor ( { id : SPATIAL_FILTERS_LAYER_ID , visible : settings . showSpatialFilters , alpha : settings . spatialFiltersAlpa , __dataRequests : [ { dataId : SOURCE_DATA_REQUEST_ID , data : featureCollection , } , ] , style : VectorStyle . createDescriptor ( { [ VECTOR_STYLES . FILL_COLOR ] : { type : STYLE_TYPE . STATIC , options : { color : settings . spatialFiltersFillColor , } , } , [ VECTOR_STYLES . LINE_COLOR ] : { type : STYLE_TYPE . STATIC , options : { color : settings . spatialFiltersLineColor , } , } , } ) , } ) , source : new GeoJsonFileSource ( geoJsonSourceDescriptor ) , } ) ; } ) ; export const getLayerList = createSelector ( getLayerListRaw , getInspectorAdapters , getChartsPaletteServiceGetColor , ( layerDescriptorList , inspectorAdapters , chartsPaletteServiceGetColor ) => { return layerDescriptorList . map ( ( layerDescriptor ) => createLayerInstance ( layerDescriptor , inspectorAdapters , chartsPaletteServiceGetColor ) ) ; } ) ; export const getLayerListConfigOnly = createSelector ( getLayerListRaw , ( layerDescriptorList ) => { return copyPersistentState ( layerDescriptorList ) ; } ) ; export function getLayerById ( layerId , state ) { return getLayerList ( state ) . find ( ( layer ) => { return layerId === layer . getId ( ) ; } ) ; } export const getHiddenLayerIds = createSelector ( getLayerListRaw , ( layers ) => layers . filter ( ( layer ) => ! layer . visible ) . map ( ( layer ) => layer . id ) ) ; export const getSelectedLayer = createSelector ( getSelectedLayerId , getLayerList , ( selectedLayerId , layerList ) => { return layerList . find ( ( layer ) => layer . getId ( ) === selectedLayerId ) ; } ) ; export const hasPreviewLayers = createSelector ( getLayerList , ( layerList ) => { return layerList . some ( ( layer ) => { return layer . isPreviewLayer ( ) ; } ) ; } ) ; export const isLoadingPreviewLayers = createSelector ( getLayerList , ( layerList ) => { return layerList . some ( ( layer ) => { return layer . isPreviewLayer ( ) && layer . isLayerLoading ( ) ; } ) ; } ) ; export const getMapColors = createSelector ( getLayerListRaw , ( layerList ) => layerList . filter ( ( layerDescriptor ) => { return ! layerDescriptor . __isPreviewLayer ; } ) . reduce ( ( accu , layerDescriptor ) => { const color = _ . get ( layerDescriptor , 'style.properties.fillColor.options.color' ) ; if ( color ) accu . push ( color ) ; return accu ; } , [ ] ) ) ; export const getSelectedLayerJoinDescriptors = createSelector ( getSelectedLayer , ( selectedLayer ) => { if ( ! selectedLayer || ! ( 'getJoins' in selectedLayer ) ) { return [ ] ; } return ( selectedLayer as IVectorLayer ) . getJoins ( ) . map ( ( join ) => { return join . toDescriptor ( ) ; } ) ; } ) ; export const getQueryableUniqueIndexPatternIds = createSelector ( getLayerList , getWaitingForMapReadyLayerListRaw , ( layerList , waitingForMapReadyLayerList ) => { const indexPatternIds = [ ] ; if ( waitingForMapReadyLayerList . length ) { waitingForMapReadyLayerList . forEach ( ( layerDescriptor ) => { const layer = createLayerInstance ( layerDescriptor ) ; if ( layer . isVisible ( ) ) { indexPatternIds . push ( ... layer . getQueryableIndexPatternIds ( ) ) ; } } ) ; } else { layerList . forEach ( ( layer ) => { if ( layer . isVisible ( ) ) { indexPatternIds . push ( ... layer . getQueryableIndexPatternIds ( ) ) ; } } ) ; } return _ . uniq ( indexPatternIds ) ; } ) ; export const getGeoFieldNames = createSelector ( getLayerList , getWaitingForMapReadyLayerListRaw , ( layerList , waitingForMapReadyLayerList ) => { const geoFieldNames = [ ] ; if ( waitingForMapReadyLayerList . length ) { waitingForMapReadyLayerList . forEach ( ( layerDescriptor ) => { const layer = createLayerInstance ( layerDescriptor ) ; geoFieldNames . push ( ... layer . getGeoFieldNames ( ) ) ; } ) ; } else { layerList . forEach ( ( layer ) => { geoFieldNames . push ( ... layer . getGeoFieldNames ( ) ) ; } ) ; } return _ . uniq ( geoFieldNames ) ; } ) ; export const hasDirtyState = createSelector ( getLayerListRaw , ( layerListRaw ) => { return layerListRaw . some ( ( layerDescriptor ) => { if ( layerDescriptor . __isPreviewLayer ) { return true ; } const trackedState = layerDescriptor [ TRACKED_LAYER_DESCRIPTOR ] ; if ( ! trackedState ) { return false ; } const currentState = copyPersistentState ( layerDescriptor ) ; return ! _ . isEqual ( currentState , trackedState ) ; } ) ; } ) ; export const areLayersLoaded = createSelector ( getLayerList , getWaitingForMapReadyLayerListRaw , getMapZoom , ( layerList , waitingForMapReadyLayerList , zoom ) => { if ( waitingForMapReadyLayerList . length ) { return false ; } for ( let i = 0 ; i < layerList . length ; i ++ ) { const layer = layerList [ i ] ; if ( layer . isVisible ( ) && layer . showAtZoomLevel ( zoom ) && ! layer . hasErrors ( ) && ! layer . isInitialDataLoadComplete ( ) ) { return false ; } } return true ; } ) ;