diff --git a/x-pack/package.json b/x-pack/package.json index 8fbb94c97c143..58ab4c22d7d15 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -217,7 +217,7 @@ "@kbn/interpreter": "1.0.0", "@kbn/ui-framework": "1.0.0", "@mapbox/geojson-rewind": "^0.4.1", - "@mapbox/mapbox-gl-draw": "^1.1.2", + "@mapbox/mapbox-gl-draw": "^1.2.0", "@mapbox/mapbox-gl-rtl-text": "^0.2.3", "@scant/router": "^0.1.0", "@slack/webhook": "^5.0.0", @@ -397,4 +397,4 @@ "cypress-multi-reporters" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js index ac28a2d5d5a6d..2daa4b2c900f5 100644 --- a/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js +++ b/x-pack/plugins/maps/public/connected_components/map/mb/draw_control/draw_control.js @@ -18,9 +18,12 @@ import { } from '../../../../elasticsearch_geo_utils'; import { DrawTooltip } from './draw_tooltip'; +const DRAW_RECTANGLE = 'draw_rectangle'; +const DRAW_CIRCLE = 'draw_circle'; + const mbDrawModes = MapboxDraw.modes; -mbDrawModes.draw_rectangle = DrawRectangle; -mbDrawModes.draw_circle = DrawCircle; +mbDrawModes[DRAW_RECTANGLE] = DrawRectangle; +mbDrawModes[DRAW_CIRCLE] = DrawCircle; export class DrawControl extends React.Component { constructor() { @@ -45,8 +48,10 @@ export class DrawControl extends React.Component { this._removeDrawControl(); } + // debounce with zero timeout needed to allow mapbox-draw finish logic to complete + // before _removeDrawControl is called _syncDrawControl = _.debounce(() => { - if (!this.props.mbMap) { + if (!this._isMounted) { return; } @@ -55,7 +60,7 @@ export class DrawControl extends React.Component { } else { this._removeDrawControl(); } - }, 256); + }, 0); _onDraw = (e) => { if (!e.features.length) { @@ -118,7 +123,7 @@ export class DrawControl extends React.Component { }; _removeDrawControl() { - if (!this._mbDrawControlAdded) { + if (!this.props.mbMap || !this._mbDrawControlAdded) { return; } @@ -129,6 +134,10 @@ export class DrawControl extends React.Component { } _updateDrawControl() { + if (!this.props.mbMap) { + return; + } + if (!this._mbDrawControlAdded) { this.props.mbMap.addControl(this._mbDrawControl); this._mbDrawControlAdded = true; @@ -136,11 +145,15 @@ export class DrawControl extends React.Component { this.props.mbMap.on('draw.create', this._onDraw); } - if (this.props.drawState.drawType === DRAW_TYPE.BOUNDS) { - this._mbDrawControl.changeMode('draw_rectangle'); - } else if (this.props.drawState.drawType === DRAW_TYPE.DISTANCE) { - this._mbDrawControl.changeMode('draw_circle'); - } else if (this.props.drawState.drawType === DRAW_TYPE.POLYGON) { + const drawMode = this._mbDrawControl.getMode(); + if (drawMode !== DRAW_RECTANGLE && this.props.drawState.drawType === DRAW_TYPE.BOUNDS) { + this._mbDrawControl.changeMode(DRAW_RECTANGLE); + } else if (drawMode !== DRAW_CIRCLE && this.props.drawState.drawType === DRAW_TYPE.DISTANCE) { + this._mbDrawControl.changeMode(DRAW_CIRCLE); + } else if ( + drawMode !== this._mbDrawControl.modes.DRAW_POLYGON && + this.props.drawState.drawType === DRAW_TYPE.POLYGON + ) { this._mbDrawControl.changeMode(this._mbDrawControl.modes.DRAW_POLYGON); } } diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/index.js b/x-pack/plugins/maps/public/routing/routes/maps_app/index.js index c5f959c54fb66..a2a4ab87affcd 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/index.js +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/index.js @@ -14,7 +14,7 @@ import { getRefreshConfig, getTimeFilters, hasDirtyState, - hasUnsavedChanges, + getLayerListConfigOnly, } from '../../../selectors/map_selectors'; import { replaceLayerList, @@ -45,9 +45,7 @@ function mapStateToProps(state = {}) { flyoutDisplay: getFlyoutDisplay(state), refreshConfig: getRefreshConfig(state), filters: getFilters(state), - hasUnsavedChanges: (savedMap, initialLayerListConfig) => { - return hasUnsavedChanges(state, savedMap, initialLayerListConfig); - }, + layerListConfigOnly: getLayerListConfigOnly(state), query: getQuery(state), timeFilters: getTimeFilters(state), }; 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 97a08f11a6757..91d00990772f4 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 @@ -103,7 +103,15 @@ export class MapsAppView extends React.Component { } _hasUnsavedChanges() { - return this.props.hasUnsavedChanges(this.props.savedMap, this.state.initialLayerListConfig); + const savedLayerList = this.props.savedMap.getLayerList(); + return !savedLayerList + ? !_.isEqual(this.props.layerListConfigOnly, this.state.initialLayerListConfig) + : // savedMap stores layerList as a JSON string using JSON.stringify. + // JSON.stringify removes undefined properties from objects. + // savedMap.getLayerList converts the JSON string back into Javascript array of objects. + // Need to perform the same process for layerListConfigOnly to compare apples to apples + // and avoid undefined properties in layerListConfigOnly triggering unsaved changes. + !_.isEqual(JSON.parse(JSON.stringify(this.props.layerListConfigOnly)), savedLayerList); } _setBreadcrumbs = () => { @@ -356,22 +364,20 @@ export class MapsAppView extends React.Component { ); } - render() { - const { filters, isFullScreen } = this.props; + _addFilter = (newFilters) => { + newFilters.forEach((filter) => { + filter.$state = { store: esFilters.FilterStateStore.APP_STATE }; + }); + this._onFiltersChange([...this.props.filters, ...newFilters]); + }; + render() { return this.state.initialized ? ( -