Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
Loading