diff --git a/x-pack/plugins/maps/public/connected_components/_index.scss b/x-pack/plugins/maps/public/connected_components/_index.scss index bd8070e8c36fd..a952b3b545922 100644 --- a/x-pack/plugins/maps/public/connected_components/_index.scss +++ b/x-pack/plugins/maps/public/connected_components/_index.scss @@ -1,4 +1,4 @@ -@import 'gis_map/gis_map'; +@import 'map_container/map_container'; @import 'layer_panel/index'; @import 'widget_overlay/index'; @import 'toolbar_overlay/index'; diff --git a/x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts b/x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts deleted file mode 100644 index 3f3fa48b3d769..0000000000000 --- a/x-pack/plugins/maps/public/connected_components/gis_map/index.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { Filter } from 'src/plugins/data/public'; - -import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; - -declare const GisMap: React.ComponentType<{ - addFilters: ((filters: Filter[]) => void) | null; - renderTooltipContent?: RenderToolTipContent; -}>; - -export { GisMap }; -// eslint-disable-next-line import/no-default-export -export default GisMap; diff --git a/x-pack/plugins/maps/public/connected_components/map/mb/index.js b/x-pack/plugins/maps/public/connected_components/map/mb/index.js index 189d6bc1f0a43..4b8df07bd1f39 100644 --- a/x-pack/plugins/maps/public/connected_components/map/mb/index.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/index.js @@ -5,7 +5,7 @@ */ import { connect } from 'react-redux'; -import { MBMapContainer } from './view'; +import { MBMap } from './view'; import { mapExtentChanged, mapReady, @@ -72,7 +72,7 @@ function mapDispatchToProps(dispatch) { }; } -const connectedMBMapContainer = connect(mapStateToProps, mapDispatchToProps, null, { +const connectedMBMap = connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true, -})(MBMapContainer); -export { connectedMBMapContainer as MBMapContainer }; +})(MBMap); +export { connectedMBMap as MBMap }; diff --git a/x-pack/plugins/maps/public/connected_components/map/mb/view.js b/x-pack/plugins/maps/public/connected_components/map/mb/view.js index d96deb226744b..d85959c3a08a4 100644 --- a/x-pack/plugins/maps/public/connected_components/map/mb/view.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/view.js @@ -26,7 +26,7 @@ import { getPreserveDrawingBuffer } from '../../../kibana_services'; mapboxgl.workerUrl = mbWorkerUrl; mapboxgl.setRTLTextPlugin(mbRtlPlugin); -export class MBMapContainer extends React.Component { +export class MBMap extends React.Component { state = { prevLayerList: undefined, hasSyncedLayerList: false, diff --git a/x-pack/plugins/maps/public/connected_components/gis_map/_gis_map.scss b/x-pack/plugins/maps/public/connected_components/map_container/_map_container.scss similarity index 100% rename from x-pack/plugins/maps/public/connected_components/gis_map/_gis_map.scss rename to x-pack/plugins/maps/public/connected_components/map_container/_map_container.scss diff --git a/x-pack/plugins/maps/public/connected_components/gis_map/index.js b/x-pack/plugins/maps/public/connected_components/map_container/index.ts similarity index 68% rename from x-pack/plugins/maps/public/connected_components/gis_map/index.js rename to x-pack/plugins/maps/public/connected_components/map_container/index.ts index b462c8aa4c02d..c3b49f1e807eb 100644 --- a/x-pack/plugins/maps/public/connected_components/gis_map/index.js +++ b/x-pack/plugins/maps/public/connected_components/map_container/index.ts @@ -4,8 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ +import { AnyAction, Dispatch } from 'redux'; import { connect } from 'react-redux'; -import { GisMap as UnconnectedGisMap } from './view'; +import { MapContainer } from './map_container'; import { getFlyoutDisplay, getIsFullScreen } from '../../selectors/ui_selectors'; import { triggerRefreshTimer, cancelAllInFlightRequests, exitFullScreen } from '../../actions'; import { @@ -15,10 +16,10 @@ import { getQueryableUniqueIndexPatternIds, isToolbarOverlayHidden, } from '../../selectors/map_selectors'; - +import { MapStoreState } from '../../reducers/store'; import { getCoreChrome } from '../../kibana_services'; -function mapStateToProps(state = {}) { +function mapStateToProps(state: MapStoreState) { return { areLayersLoaded: areLayersLoaded(state), flyoutDisplay: getFlyoutDisplay(state), @@ -30,17 +31,16 @@ function mapStateToProps(state = {}) { }; } -function mapDispatchToProps(dispatch) { +function mapDispatchToProps(dispatch: Dispatch<AnyAction>) { return { - triggerRefreshTimer: () => dispatch(triggerRefreshTimer()), + triggerRefreshTimer: () => dispatch<any>(triggerRefreshTimer()), exitFullScreen: () => { dispatch(exitFullScreen()); getCoreChrome().setIsVisible(true); }, - cancelAllInFlightRequests: () => dispatch(cancelAllInFlightRequests()), + cancelAllInFlightRequests: () => dispatch<any>(cancelAllInFlightRequests()), }; } -const connectedGisMap = connect(mapStateToProps, mapDispatchToProps)(UnconnectedGisMap); -export { connectedGisMap as GisMap }; // GisMap is pulled in by name by the Maps-app itself -export default connectedGisMap; //lazy-loading in the embeddable requires default export +const connected = connect(mapStateToProps, mapDispatchToProps)(MapContainer); +export { connected as MapContainer }; diff --git a/x-pack/plugins/maps/public/connected_components/gis_map/view.js b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx similarity index 70% rename from x-pack/plugins/maps/public/connected_components/gis_map/view.js rename to x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index 7199620d69fcf..beb1eb0947c50 100644 --- a/x-pack/plugins/maps/public/connected_components/gis_map/view.js +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -7,27 +7,63 @@ import _ from 'lodash'; import React, { Component } from 'react'; import classNames from 'classnames'; -import { MBMapContainer } from '../map/mb'; +import { EuiFlexGroup, EuiFlexItem, EuiCallOut } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import uuid from 'uuid/v4'; +import { Filter } from 'src/plugins/data/public'; +// @ts-expect-error +import { MBMap } from '../map/mb'; +// @ts-expect-error import { WidgetOverlay } from '../widget_overlay'; +// @ts-expect-error import { ToolbarOverlay } from '../toolbar_overlay'; +// @ts-expect-error import { LayerPanel } from '../layer_panel'; import { AddLayerPanel } from '../add_layer_panel'; -import { EuiFlexGroup, EuiFlexItem, EuiCallOut } from '@elastic/eui'; import { ExitFullScreenButton } from '../../../../../../src/plugins/kibana_react/public'; import { getIndexPatternsFromIds } from '../../index_pattern_util'; import { ES_GEO_FIELD_TYPE } from '../../../common/constants'; import { indexPatterns as indexPatternsUtils } from '../../../../../../src/plugins/data/public'; -import { i18n } from '@kbn/i18n'; -import uuid from 'uuid/v4'; import { FLYOUT_STATE } from '../../reducers/ui'; import { MapSettingsPanel } from '../map_settings_panel'; import { registerLayerWizards } from '../../classes/layers/load_layer_wizards'; +import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; +import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; +import { MapRefreshConfig } from '../../../common/descriptor_types'; import 'mapbox-gl/dist/mapbox-gl.css'; const RENDER_COMPLETE_EVENT = 'renderComplete'; -export class GisMap extends Component { - state = { +interface Props { + addFilters: ((filters: Filter[]) => void) | null; + areLayersLoaded: boolean; + cancelAllInFlightRequests: () => void; + exitFullScreen: () => void; + flyoutDisplay: FLYOUT_STATE; + hideToolbarOverlay: boolean; + isFullScreen: boolean; + indexPatternIds: string[]; + mapInitError: string | null | undefined; + refreshConfig: MapRefreshConfig; + renderTooltipContent?: RenderToolTipContent; + triggerRefreshTimer: () => void; +} + +interface State { + isInitialLoadRenderTimeoutComplete: boolean; + domId: string; + geoFields: GeoFieldWithIndex[]; +} + +export class MapContainer extends Component<Props, State> { + private _isMounted: boolean = false; + private _isInitalLoadRenderTimerStarted: boolean = false; + private _prevIndexPatternIds: string[] = []; + private _refreshTimerId: number | null = null; + private _prevIsPaused: boolean | null = null; + private _prevInterval: number | null = null; + + state: State = { isInitialLoadRenderTimeoutComplete: false, domId: uuid(), geoFields: [], @@ -35,7 +71,6 @@ export class GisMap extends Component { componentDidMount() { this._isMounted = true; - this._isInitalLoadRenderTimerStarted = false; this._setRefreshTimer(); registerLayerWizards(); } @@ -73,7 +108,7 @@ export class GisMap extends Component { } }; - _loadGeoFields = async (nextIndexPatternIds) => { + _loadGeoFields = async (nextIndexPatternIds: string[]) => { if (_.isEqual(nextIndexPatternIds, this._prevIndexPatternIds)) { // all ready loaded index pattern ids return; @@ -81,29 +116,24 @@ export class GisMap extends Component { this._prevIndexPatternIds = nextIndexPatternIds; - const geoFields = []; - try { - const indexPatterns = await getIndexPatternsFromIds(nextIndexPatternIds); - indexPatterns.forEach((indexPattern) => { - indexPattern.fields.forEach((field) => { - if ( - !indexPatternsUtils.isNestedField(field) && - (field.type === ES_GEO_FIELD_TYPE.GEO_POINT || - field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE) - ) { - geoFields.push({ - geoFieldName: field.name, - geoFieldType: field.type, - indexPatternTitle: indexPattern.title, - indexPatternId: indexPattern.id, - }); - } - }); + const geoFields: GeoFieldWithIndex[] = []; + const indexPatterns = await getIndexPatternsFromIds(nextIndexPatternIds); + indexPatterns.forEach((indexPattern) => { + indexPattern.fields.forEach((field) => { + if ( + indexPattern.id && + !indexPatternsUtils.isNestedField(field) && + (field.type === ES_GEO_FIELD_TYPE.GEO_POINT || field.type === ES_GEO_FIELD_TYPE.GEO_SHAPE) + ) { + geoFields.push({ + geoFieldName: field.name, + geoFieldType: field.type, + indexPatternTitle: indexPattern.title, + indexPatternId: indexPattern.id, + }); + } }); - } catch (e) { - // swallow errors. - // the Layer-TOC will indicate which layers are disfunctional on a per-layer basis - } + }); if (!this._isMounted) { return; @@ -115,33 +145,34 @@ export class GisMap extends Component { _setRefreshTimer = () => { const { isPaused, interval } = this.props.refreshConfig; - if (this.isPaused === isPaused && this.interval === interval) { + if (this._prevIsPaused === isPaused && this._prevInterval === interval) { // refreshConfig is the same, nothing to do return; } - this.isPaused = isPaused; - this.interval = interval; + this._prevIsPaused = isPaused; + this._prevInterval = interval; this._clearRefreshTimer(); if (!isPaused && interval > 0) { - this.refreshTimerId = setInterval(() => { + this._refreshTimerId = window.setInterval(() => { this.props.triggerRefreshTimer(); }, interval); } }; _clearRefreshTimer = () => { - if (this.refreshTimerId) { - clearInterval(this.refreshTimerId); + if (this._refreshTimerId) { + window.clearInterval(this._refreshTimerId); + this._refreshTimerId = null; } }; // Mapbox does not provide any feedback when rendering is complete. // Temporary solution is just to wait set period of time after data has loaded. _startInitialLoadRenderTimer = () => { - setTimeout(() => { + window.setTimeout(() => { if (this._isMounted) { this.setState({ isInitialLoadRenderTimeoutComplete: true }); this._onInitialLoadRenderComplete(); @@ -159,8 +190,6 @@ export class GisMap extends Component { renderTooltipContent, } = this.props; - const { domId } = this.state; - if (mapInitError) { return ( <div data-render-complete data-shared-item> @@ -194,12 +223,12 @@ export class GisMap extends Component { <EuiFlexGroup gutterSize="none" responsive={false} - data-dom-id={domId} + data-dom-id={this.state.domId} data-render-complete={this.state.isInitialLoadRenderTimeoutComplete} data-shared-item > <EuiFlexItem className="mapMapWrapper"> - <MBMapContainer + <MBMap addFilters={addFilters} geoFields={this.state.geoFields} renderTooltipContent={renderTooltipContent} diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 6f58339792214..137b3a31b795b 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -5,12 +5,11 @@ */ import _ from 'lodash'; -import React, { Suspense, lazy } from 'react'; +import React from 'react'; import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subscription } from 'rxjs'; import { Unsubscribe } from 'redux'; -import { EuiLoadingSpinner } from '@elastic/eui'; import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public'; import { APPLY_FILTER_TRIGGER } from '../../../../../src/plugins/ui_actions/public'; import { @@ -50,11 +49,11 @@ import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; import { getUiActions, getCoreI18n } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; +import { MapContainer } from '../connected_components/map_container'; import { MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from './types'; export { MapEmbeddableInput, MapEmbeddableConfig }; -const GisMap = lazy(() => import('../connected_components/gis_map')); export class MapEmbeddable extends Embeddable<MapEmbeddableInput, MapEmbeddableOutput> { type = MAP_SAVED_OBJECT_TYPE; @@ -223,12 +222,10 @@ export class MapEmbeddable extends Embeddable<MapEmbeddableInput, MapEmbeddableO render( <Provider store={this._store}> <I18nContext> - <Suspense fallback={<EuiLoadingSpinner />}> - <GisMap - addFilters={this.input.hideFilterActions ? null : this.addFilters} - renderTooltipContent={this._renderTooltipContent} - /> - </Suspense> + <MapContainer + addFilters={this.input.hideFilterActions ? null : this.addFilters} + renderTooltipContent={this._renderTooltipContent} + /> </I18nContext> </Provider>, this._domNode diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js b/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js index bccfdbf2467d6..b26c44df25104 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js @@ -30,7 +30,7 @@ import { import { AppStateManager } from '../../state_syncing/app_state_manager'; import { useAppStateSyncing } from '../../state_syncing/app_sync'; import { esFilters } from '../../../../../../../src/plugins/data/public'; -import { GisMap } from '../../../connected_components/gis_map'; +import { MapContainer } from '../../../connected_components/map_container'; import { goToSpecifiedPath } from '../../maps_router'; const unsavedChangesWarning = i18n.translate('xpack.maps.breadCrumbs.unsavedChangesWarning', { @@ -464,7 +464,7 @@ export class MapsAppView extends React.Component { {this._renderTopNav()} <h1 className="euiScreenReaderOnly">{`screenTitle placeholder`}</h1> <div id="react-maps-root"> - <GisMap + <MapContainer addFilters={(newFilters) => { newFilters.forEach((filter) => { filter.$state = { store: esFilters.FilterStateStore.APP_STATE };