Skip to content

Commit

Permalink
[Maps] Provide ability to create MapEmbeddable directly from a map co…
Browse files Browse the repository at this point in the history
…nfiguration (#43878) (#44044)

* [Maps] Provide ability to create MapEmbeddable directly from a map configuration

* call updateInput instead of passing modified input to MapEmbeddable constructor

* cleanup i18n translations

* update map embeddable documenation to reflect createFromState examples
  • Loading branch information
nreese authored Aug 27, 2019
1 parent 901dce9 commit 900c1ff
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { EMSTMSSource } from '../layers/sources/ems_tms_source';
import chrome from 'ui/chrome';
import { getKibanaTileMap } from '../meta';

export function getInitialLayers(savedMapLayerListJSON) {
export function getInitialLayers(layerListJSON) {

if (savedMapLayerListJSON) {
return JSON.parse(savedMapLayerListJSON);
if (layerListJSON) {
return JSON.parse(layerListJSON);
}

const tilemapSourceFromKibana = getKibanaTileMap();
Expand Down
38 changes: 38 additions & 0 deletions x-pack/legacy/plugins/maps/public/embeddable/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

### Map specific `input` parameters
- **hideFilterActions:** (Boolean) Set to true to hide all filtering controls.
- **isLayerTOCOpen:** (Boolean) Set to false to render map with legend in collapsed state.
- **openTOCDetails:** (Array of Strings) Array of layer ids. Add layer id to show layer details on initial render.
- **mapCenter:** ({lat, lon, zoom }) Provide mapCenter to customize initial map location.

### Creating a Map embeddable from saved object
```
const factory = new MapEmbeddableFactory();
const input = {
hideFilterActions: true,
isLayerTOCOpen: false,
openTOCDetails: ['tfi3f', 'edh66'],
mapCenter: { lat: 0.0, lon: 0.0, zoom: 7 }
}
const mapEmbeddable = await factory.createFromSavedObject(
'de71f4f0-1902-11e9-919b-ffe5949a18d2',
input,
parent
);
```

### Creating a Map embeddable from state
```
const factory = new MapEmbeddableFactory();
const state = {
layerList: [], // where layerList is same as saved object layerListJSON property (unstringified)
title: 'my map',
}
const input = {
hideFilterActions: true,
isLayerTOCOpen: false,
openTOCDetails: ['tfi3f', 'edh66'],
mapCenter: { lat: 0.0, lon: 0.0, zoom: 7 }
}
const mapEmbeddable = await factory.createFromState(state, input, parent);
```
25 changes: 5 additions & 20 deletions x-pack/legacy/plugins/maps/public/embeddable/map_embeddable.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@ import { I18nContext } from 'ui/i18n';

import { GisMap } from '../connected_components/gis_map';
import { createMapStore } from '../reducers/store';
import { getInitialLayers } from '../angular/get_initial_layers';
import {
setGotoWithCenter,
replaceLayerList,
setQuery,
setRefreshConfig,
disableScrollZoom,
} from '../actions/map_actions';
import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui';
import {
setReadOnly,
setIsLayerTOCOpen,
Expand All @@ -47,11 +45,11 @@ export class MapEmbeddable extends Embeddable {
editUrl: config.editUrl,
indexPatterns: config.indexPatterns,
editable: config.editable,
defaultTitle: config.savedMap.title
defaultTitle: config.title
},
parent);

this._savedMap = config.savedMap;
this._layerList = config.layerList;
this._store = createMapStore();

this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input));
Expand Down Expand Up @@ -103,16 +101,10 @@ export class MapEmbeddable extends Embeddable {

if (_.has(this.input, 'isLayerTOCOpen')) {
this._store.dispatch(setIsLayerTOCOpen(this.input.isLayerTOCOpen));
} else if (this._savedMap.uiStateJSON) {
const uiState = JSON.parse(this._savedMap.uiStateJSON);
this._store.dispatch(setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN)));
}

if (_.has(this.input, 'openTOCDetails')) {
this._store.dispatch(setOpenTOCDetails(this.input.openTOCDetails));
} else if (this._savedMap.uiStateJSON) {
const uiState = JSON.parse(this._savedMap.uiStateJSON);
this._store.dispatch(setOpenTOCDetails(_.get(uiState, 'openTOCDetails', [])));
}

if (this.input.mapCenter) {
Expand All @@ -121,16 +113,9 @@ export class MapEmbeddable extends Embeddable {
lon: this.input.mapCenter.lon,
zoom: this.input.mapCenter.zoom,
}));
} else if (this._savedMap.mapStateJSON) {
const mapState = JSON.parse(this._savedMap.mapStateJSON);
this._store.dispatch(setGotoWithCenter({
lat: mapState.center.lat,
lon: mapState.center.lon,
zoom: mapState.zoom,
}));
}
const layerList = getInitialLayers(this._savedMap.layerListJSON);
this._store.dispatch(replaceLayerList(layerList));

this._store.dispatch(replaceLayerList(this._layerList));
this._dispatchSetQuery(this.input);
this._dispatchSetRefreshConfig(this.input);

Expand Down Expand Up @@ -162,7 +147,7 @@ export class MapEmbeddable extends Embeddable {
if (this._unsubscribeFromStore) {
this._unsubscribeFromStore();
}
this._savedMap.destroy();

if (this._domNode) {
unmountComponentAtNode(this._domNode);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { createMapPath, MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/con
import { createMapStore } from '../reducers/store';
import { addLayerWithoutDataSync } from '../actions/map_actions';
import { getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors';
import { getInitialLayers } from '../angular/get_initial_layers';
import { mergeInputWithSavedMap } from './merge_input_with_saved_map';
import '../angular/services/gis_map_saved_object_loader';
import 'ui/vis/map/service_settings';

Expand Down Expand Up @@ -50,19 +52,20 @@ export class MapEmbeddableFactory extends EmbeddableFactory {
});
}

async _getIndexPatterns(layerListJSON) {
async _getIndexPatterns(layerList) {
// Need to extract layerList from store to get queryable index pattern ids
const store = createMapStore();
let queryableIndexPatternIds;
try {
JSON.parse(layerListJSON).forEach(layerDescriptor => {
layerList.forEach(layerDescriptor => {
store.dispatch(addLayerWithoutDataSync(layerDescriptor));
});
queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(store.getState());
} catch (error) {
throw new Error(i18n.translate('xpack.maps.mapEmbeddableFactory', {
defaultMessage: 'Unable to load map, malformed saved object',
throw new Error(i18n.translate('xpack.maps.mapEmbeddableFactory.invalidLayerList', {
defaultMessage: 'Unable to load map, malformed layer list',
}));
}
const queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(store.getState());

const promises = queryableIndexPatternIds.map(async (indexPatternId) => {
try {
Expand All @@ -77,32 +80,68 @@ export class MapEmbeddableFactory extends EmbeddableFactory {
return _.compact(indexPatterns);
}

async _fetchSavedMap(savedObjectId) {
const $injector = await chrome.dangerouslyGetActiveInjector();
const savedObjectLoader = $injector.get('gisMapSavedObjectLoader');
return await savedObjectLoader.get(savedObjectId);
}

async createFromSavedObject(
savedObjectId,
input,
parent
) {
const $injector = await chrome.dangerouslyGetActiveInjector();
const savedObjectLoader = $injector.get('gisMapSavedObjectLoader');

const savedMap = await savedObjectLoader.get(savedObjectId);
const indexPatterns = await this._getIndexPatterns(savedMap.layerListJSON);
const savedMap = await this._fetchSavedMap(savedObjectId);
const layerList = getInitialLayers(savedMap.layerListJSON);
const indexPatterns = await this._getIndexPatterns(layerList);

return new MapEmbeddable(
const embeddable = new MapEmbeddable(
{
savedMap,
layerList,
title: savedMap.title,
editUrl: chrome.addBasePath(createMapPath(savedObjectId)),
indexPatterns,
editable: this.isEditable(),
},
input,
parent
);

try {
embeddable.updateInput(mergeInputWithSavedMap(input, savedMap));
} catch (error) {
throw new Error(i18n.translate('xpack.maps.mapEmbeddableFactory.invalidSavedObject', {
defaultMessage: 'Unable to load map, malformed saved object',
}));
}

return embeddable;
}

async createFromState(
state,
input,
parent
) {
const layerList = state && state.layerList ? state.layerList : getInitialLayers();
const indexPatterns = await this._getIndexPatterns(layerList);

return new MapEmbeddable(
{
layerList,
title: state && state.title ? state.title : '',
editUrl: null,
indexPatterns,
editable: false,
},
input,
parent
);
}

async create(input) {
window.location.href = chrome.addBasePath(createMapPath(''));
return new ErrorEmbeddable('Maps can only be created from a saved object', input);
return new ErrorEmbeddable('Maps can only be created with createFromSavedObject or createFromState', input);
}
}

Expand Down
27 changes: 0 additions & 27 deletions x-pack/legacy/plugins/maps/public/embeddable/map_embeddables.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 _ from 'lodash';
import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui';

const MAP_EMBEDDABLE_INPUT_KEYS = [
'hideFilterActions',
'isLayerTOCOpen',
'openTOCDetails',
'mapCenter'
];

export function mergeInputWithSavedMap(input, savedMap) {
const mergedInput = _.pick(input, MAP_EMBEDDABLE_INPUT_KEYS);

if (!_.has(input, 'isLayerTOCOpen') && savedMap.uiStateJSON) {
const uiState = JSON.parse(savedMap.uiStateJSON);
mergedInput.isLayerTOCOpen = _.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN);
}

if (!_.has(input, 'openTOCDetails') && savedMap.uiStateJSON) {
const uiState = JSON.parse(savedMap.uiStateJSON);
if (_.has(uiState, 'openTOCDetails')) {
mergedInput.openTOCDetails = _.get(uiState, 'openTOCDetails', []);
}
}

if (!input.mapCenter && savedMap.mapStateJSON) {
const mapState = JSON.parse(savedMap.mapStateJSON);
mergedInput.mapCenter = {
lat: mapState.center.lat,
lon: mapState.center.lon,
zoom: mapState.zoom,
};
}

return mergedInput;
}
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -5531,7 +5531,6 @@
"xpack.maps.mapController.saveMapButtonLabel": "保存",
"xpack.maps.mapController.saveMapDescription": "マップを保存",
"xpack.maps.mapController.saveSuccessMessage": "「{title}」が保存されました",
"xpack.maps.mapEmbeddableFactory": "マップを読み込めません。奇形の保存されたオブジェクト",
"xpack.maps.mapListing.advancedSettingsLinkText": "高度な設定",
"xpack.maps.mapListing.cancelTitle": "キャンセル",
"xpack.maps.mapListing.createMapButtonLabel": "マップを作成",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -5675,7 +5675,6 @@
"xpack.maps.mapController.saveMapButtonLabel": "保存",
"xpack.maps.mapController.saveMapDescription": "保存地图",
"xpack.maps.mapController.saveSuccessMessage": "已保存“{title}”",
"xpack.maps.mapEmbeddableFactory": "无法加载地图,已保存对象格式错误",
"xpack.maps.mapListing.advancedSettingsLinkText": "高级设置",
"xpack.maps.mapListing.cancelTitle": "取消",
"xpack.maps.mapListing.createMapButtonLabel": "创建地图",
Expand Down

0 comments on commit 900c1ff

Please sign in to comment.