From 3247f86da6fba1b4203936203d9d4c110a812ea7 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 26 Oct 2020 15:45:50 -0600 Subject: [PATCH 01/35] [Maps] saved objects by value --- .../embeddable/embeddable_factory.ts | 4 +- .../maps/public/embeddable/map_embeddable.tsx | 173 ++++++++++++++---- .../embeddable/map_embeddable_factory.ts | 99 +--------- .../merge_input_with_saved_map.d.ts | 12 -- .../embeddable/merge_input_with_saved_map.js | 43 ----- .../plugins/maps/public/embeddable/types.ts | 32 ++-- .../maps/public/lazy_load_bundle/index.ts | 31 ---- .../public/lazy_load_bundle/lazy/index.ts | 7 - .../maps/public/map_attribute_service.ts | 71 +++++++ 9 files changed, 227 insertions(+), 245 deletions(-) delete mode 100644 x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts delete mode 100644 x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js create mode 100644 x-pack/plugins/maps/public/map_attribute_service.ts diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts index 65e9c22d24eaf..aea783fce0e96 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts @@ -44,7 +44,9 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { getIconForSavedObject: () => 'lensApp', }; - constructor(private getStartServices: () => Promise) {} + constructor(private getStartServices: () => Promise) { + console.log(getStartServices); + } public isEditable = async () => { const { capabilities } = await this.getStartServices(); diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index f20656545d09a..fb5572673799d 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -10,7 +10,7 @@ import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subscription } from 'rxjs'; import { Unsubscribe } from 'redux'; -import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public'; +import { Embeddable, IContainer, ReferenceOrValueEmbeddable } from '../../../../../src/plugins/embeddable/public'; import { ACTION_GLOBAL_APPLY_FILTER } from '../../../../../src/plugins/data/public'; import { APPLY_FILTER_TRIGGER, @@ -27,6 +27,7 @@ import { import { createMapStore, MapStore } from '../reducers/store'; import { MapSettings } from '../reducers/map'; import { + addLayerWithoutDataSync, setGotoWithCenter, replaceLayerList, setQuery, @@ -49,23 +50,30 @@ import { setEventHandlers, EventHandlers, } from '../reducers/non_serializable_instances'; -import { getMapCenter, getMapZoom, getHiddenLayerIds } from '../selectors/map_selectors'; -import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; +import { getMapCenter, getMapZoom, getHiddenLayerIds, getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors'; +import { APP_ID, getExistingMapPath, MAP_SAVED_OBJECT_TYPE, MAP_PATH } from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; -import { getUiActions, getCoreI18n } from '../kibana_services'; +import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; +import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapContainer } from '../connected_components/map_container'; +import { getMapAttributeService } from '../map_attribute_service'; +import { getInitialLayers } from '../routing/bootstrap/get_initial_layers'; +export { getIndexPatternsFromIds } from '../index_pattern_util'; +import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; -import { MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from './types'; -export { MapEmbeddableInput, MapEmbeddableConfig }; +import { MapByValueInput, MapByReferenceInput, MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from './types'; +export { MapEmbeddableInput }; -export class MapEmbeddable extends Embeddable { +const attributeService = getMapAttributeService(); + +export class MapEmbeddable + extends Embeddable + implements ReferenceOrValueEmbeddable { type = MAP_SAVED_OBJECT_TYPE; - private _description: string; + private _attributes: MapSavedObjectAttributes | null = null; private _renderTooltipContent?: RenderToolTipContent; - private _eventHandlers?: EventHandlers; - private _layerList: LayerDescriptor[]; private _store: MapStore; private _subscription: Subscription; private _prevTimeRange?: TimeRange; @@ -74,43 +82,81 @@ export class MapEmbeddable extends Embeddable { + this._handleStoreChanges(); + }); + + this.loadMapAttributes(initialInput); this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input)); } + private async loadMapAttributes(input: MapEmbeddableInput) { + this._attributes = await attributeService.unwrapAttributes(input); + const layerList = getInitialLayers(this._attributes.layerListJSON); + this.setLayerList(layerList); + this.initializeOutput(); + this._isInitialized = true; + if (this._domNode) { + this.render(this._domNode); + } + } + + private initializeOutput() { + const savedMapTitle = this._attributes?.title ? this._attributes.title : '' + const input = this.getInput(); + const title = input.hidePanelTitles ? '' : input.title || savedMapTitle; + const savedObjectId = (input as MapByReferenceInput).savedObjectId; + this.updateOutput({ + ...this.getOutput(), + defaultTitle: savedMapTitle, + title, + editPath: `/${MAP_PATH}/${savedObjectId}`, + editUrl: getHttp().basePath.prepend(getExistingMapPath(savedObjectId)), + }); + } + + public inputIsRefType( + input: MapByValueInput | MapByReferenceInput + ): input is MapByReferenceInput { + return attributeService.inputIsRefType(input); + }; + + public async getInputAsRefType(): Promise { + const input = attributeService.getExplicitInputFromEmbeddable(this); + return attributeService.getInputAsRefType(input, { + showSaveModal: true, + saveModalTitle: this.getTitle(), + }); + }; + + public async getInputAsValueType(): Promise { + const input = attributeService.getExplicitInputFromEmbeddable(this); + return attributeService.getInputAsValueType(input); + }; + public getDescription() { - return this._description; + return this._attributes?.description; } - supportedTriggers(): Array { + public supportedTriggers(): Array { return [APPLY_FILTER_TRIGGER]; } @@ -119,7 +165,7 @@ export class MapEmbeddable extends Embeddable { - this._eventHandlers = eventHandlers; + this._store.dispatch(setEventHandlers(eventHandlers)); }; getInspectorAdapters() { @@ -180,21 +226,42 @@ export class MapEmbeddable extends Embeddable(replaceLayerList(this._layerList)); if (this.input.hiddenLayers) { this._store.dispatch(setHiddenLayers(this.input.hiddenLayers)); } this._dispatchSetQuery(this.input); this._dispatchSetRefreshConfig(this.input); - this._domNode = domNode; - const I18nContext = getCoreI18n().Context; render( @@ -251,15 +324,35 @@ export class MapEmbeddable extends Embeddable, this._domNode ); + } - this._unsubscribeFromStore = this._store.subscribe(() => { - this._handleStoreChanges(); - }); + setLayerList(layerList: LayerDescriptor[]) { + this.setIndexPatterns(layerList); + this._store.dispatch(replaceLayerList(layerList)); } - async setLayerList(layerList: LayerDescriptor[]) { - this._layerList = layerList; - return await this._store.dispatch(replaceLayerList(this._layerList)); + private async setIndexPatterns(layerList: LayerDescriptor[]) { + let queryableIndexPatternIds: string[]; + try { + const tempStore = createMapStore(); + layerList.forEach((layerDescriptor: LayerDescriptor) => { + tempStore.dispatch(addLayerWithoutDataSync(layerDescriptor)); + }); + queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(tempStore.getState()); + } catch (error) { + throw new Error( + i18n.translate('xpack.maps.mapEmbeddable.invalidLayerList', { + defaultMessage: 'Unable to set map embeddable layer list, invalid layer list', + }) + ); + } + //console.log('getIndexPatternsFromIds', getIndexPatternsFromIds); + //const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); + //console.log('indexPatterns', indexPatterns); + this.updateOutput({ + ...this.getOutput(), + indexPatterns: [], + }); } addFilters = async (filters: Filter[], actionId: string = ACTION_GLOBAL_APPLY_FILTER) => { diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts index b49419487b6fa..836598b70dd94 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -4,23 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { IIndexPattern } from 'src/plugins/data/public'; import { EmbeddableFactoryDefinition, IContainer, } from '../../../../../src/plugins/embeddable/public'; import '../index.scss'; import { - getExistingMapPath, MAP_SAVED_OBJECT_TYPE, APP_ICON, - APP_ID, - MAP_PATH, } from '../../common/constants'; import { LayerDescriptor } from '../../common/descriptor_types'; -import { MapEmbeddableInput } from './types'; +import { MapByValueInput, MapByReferenceInput, MapEmbeddableInput } from './types'; import { lazyLoadMapModules } from '../lazy_load_bundle'; export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { @@ -49,105 +44,25 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { }); } - async _getIndexPatterns(layerList: LayerDescriptor[]): Promise { - // Need to extract layerList from store to get queryable index pattern ids - const { - addLayerWithoutDataSync, - createMapStore, - getIndexPatternsFromIds, - getQueryableUniqueIndexPatternIds, - } = await lazyLoadMapModules(); - const store = createMapStore(); - let queryableIndexPatternIds: string[]; - try { - layerList.forEach((layerDescriptor: LayerDescriptor) => { - store.dispatch(addLayerWithoutDataSync(layerDescriptor)); - }); - queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(store.getState()); - } catch (error) { - throw new Error( - i18n.translate('xpack.maps.mapEmbeddableFactory.invalidLayerList', { - defaultMessage: 'Unable to load map, malformed layer list', - }) - ); - } - - const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); - return _.compact(indexPatterns) as IIndexPattern[]; - } - - async _fetchSavedMap(savedObjectId: string) { - const { getMapsSavedObjectLoader } = await lazyLoadMapModules(); - const savedObjectLoader = getMapsSavedObjectLoader(); - return await savedObjectLoader.get(savedObjectId); - } - createFromSavedObject = async ( savedObjectId: string, input: MapEmbeddableInput, parent?: IContainer ) => { - const { - getInitialLayers, - getHttp, - MapEmbeddable, - mergeInputWithSavedMap, - } = await lazyLoadMapModules(); - const savedMap = await this._fetchSavedMap(savedObjectId); - const layerList = getInitialLayers(savedMap.layerListJSON); - const indexPatterns = await this._getIndexPatterns(layerList); - - let settings; - if (savedMap.mapStateJSON) { - const mapState = JSON.parse(savedMap.mapStateJSON); - if (mapState.settings) { - settings = mapState.settings; - } - } - - const embeddable = new MapEmbeddable( - { - layerList, - title: savedMap.title, - description: savedMap.description, - editUrl: getHttp().basePath.prepend(getExistingMapPath(savedObjectId)), - editApp: APP_ID, - editPath: `/${MAP_PATH}/${savedObjectId}`, - indexPatterns, - editable: await this.isEditable(), - settings, - }, - 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', - }) - ); + if (!(input as MapByReferenceInput).savedObjectId) { + (input as MapByReferenceInput).savedObjectId = savedObjectId; } - - return embeddable; + return this.create(input, parent); }; create = async (input: MapEmbeddableInput, parent?: IContainer) => { - const { getInitialLayers, MapEmbeddable } = await lazyLoadMapModules(); - const layerList = getInitialLayers(); - const indexPatterns = await this._getIndexPatterns(layerList); - + const { MapEmbeddable } = await lazyLoadMapModules(); return new MapEmbeddable( { - layerList, - title: input.title ?? '', - indexPatterns, - editable: false, + editable: await this.isEditable() }, input, - parent + parent, ); }; } diff --git a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts b/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts deleted file mode 100644 index 4ce4df02f6a39..0000000000000 --- a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.d.ts +++ /dev/null @@ -1,12 +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 { MapEmbeddableInput } from './map_embeddable'; - -export function mergeInputWithSavedMap( - input: MapEmbeddableInput, - savedmap: unknown -): Partial; diff --git a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js b/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js deleted file mode 100644 index d91c91b3b223c..0000000000000 --- a/x-pack/plugins/maps/public/embeddable/merge_input_with_saved_map.js +++ /dev/null @@ -1,43 +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 _ 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; -} diff --git a/x-pack/plugins/maps/public/embeddable/types.ts b/x-pack/plugins/maps/public/embeddable/types.ts index 8ba906111ad1e..baa4de34dedc2 100644 --- a/x-pack/plugins/maps/public/embeddable/types.ts +++ b/x-pack/plugins/maps/public/embeddable/types.ts @@ -6,28 +6,17 @@ import { IIndexPattern } from '../../../../../src/plugins/data/common/index_patterns'; import { MapSettings } from '../reducers/map'; -import { EmbeddableInput, EmbeddableOutput } from '../../../../../src/plugins/embeddable/public'; +import { EmbeddableInput, EmbeddableOutput, SavedObjectEmbeddableInput } from '../../../../../src/plugins/embeddable/public'; import { Filter, Query, RefreshInterval, TimeRange } from '../../../../../src/plugins/data/common'; import { LayerDescriptor, MapCenterAndZoom } from '../../common/descriptor_types'; -export interface MapEmbeddableConfig { - description?: string; - editUrl?: string; - editApp?: string; - editPath?: string; - indexPatterns: IIndexPattern[]; +export type MapEmbeddableConfig = { editable: boolean; - title?: string; - layerList: LayerDescriptor[]; - settings?: MapSettings; -} +}; -export interface MapEmbeddableInput extends EmbeddableInput { - timeRange?: TimeRange; - filters: Filter[]; - query?: Query; - refreshConfig: RefreshInterval; - isLayerTOCOpen: boolean; +type MapEmbeddableState = { + refreshConfig?: RefreshInterval; + isLayerTOCOpen?: boolean; openTOCDetails?: string[]; disableTooltipControl?: boolean; disableInteractive?: boolean; @@ -37,8 +26,13 @@ export interface MapEmbeddableInput extends EmbeddableInput { mapCenter?: MapCenterAndZoom; hiddenLayers?: string[]; hideFilterActions?: boolean; -} +}; +export type MapByValueInput = { + attributes: MapSavedObjectAttributes; +} & EmbeddableInput & MapEmbeddableState; +export type MapByReferenceInput = SavedObjectEmbeddableInput & MapEmbeddableState; +export type MapEmbeddableInput = MapByValueInput | MapByReferenceInput; -export interface MapEmbeddableOutput extends EmbeddableOutput { +export type MapEmbeddableOutput = EmbeddableOutput & { indexPatterns: IIndexPattern[]; } diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts index 9fbe090633747..30f9c1d7838cd 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts @@ -12,8 +12,6 @@ import { IndexPattern } from 'src/plugins/data/public'; import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapStore, MapStoreState } from '../reducers/store'; -import { EventHandlers } from '../reducers/non_serializable_instances'; -import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; import { MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from '../embeddable/types'; import { SourceRegistryEntry } from '../classes/sources/source_registry'; import { LayerWizard } from '../classes/layers/layer_wizard_registry'; @@ -21,25 +19,13 @@ import { LayerWizard } from '../classes/layers/layer_wizard_registry'; let loadModulesPromise: Promise; interface LazyLoadedMapModules { - getMapsSavedObjectLoader: any; MapEmbeddable: new ( config: MapEmbeddableConfig, initialInput: MapEmbeddableInput, parent?: IContainer, - renderTooltipContent?: RenderToolTipContent, - eventHandlers?: EventHandlers ) => Embeddable; getIndexPatternService: () => IndexPatternsContract; - getHttp: () => any; getMapsCapabilities: () => any; - createMapStore: () => MapStore; - addLayerWithoutDataSync: (layerDescriptor: LayerDescriptor) => AnyAction; - getQueryableUniqueIndexPatternIds: (state: MapStoreState) => string[]; - getInitialLayers: ( - layerListJSON?: string, - initialLayers?: LayerDescriptor[] - ) => LayerDescriptor[]; - mergeInputWithSavedMap: any; renderApp: (params: AppMountParameters) => Promise<() => void>; createSecurityLayerDescriptors: ( indexPatternId: string, @@ -47,7 +33,6 @@ interface LazyLoadedMapModules { ) => LayerDescriptor[]; registerLayerWizard: (layerWizard: LayerWizard) => void; registerSource(entry: SourceRegistryEntry): void; - getIndexPatternsFromIds: (indexPatternIds: string[]) => Promise; createTileMapLayerDescriptor: ({ label, mapType, @@ -95,41 +80,25 @@ export async function lazyLoadMapModules(): Promise { loadModulesPromise = new Promise(async (resolve) => { const { - getMapsSavedObjectLoader, - getQueryableUniqueIndexPatternIds, MapEmbeddable, getIndexPatternService, - getHttp, getMapsCapabilities, - createMapStore, - addLayerWithoutDataSync, - getInitialLayers, - mergeInputWithSavedMap, renderApp, createSecurityLayerDescriptors, registerLayerWizard, registerSource, - getIndexPatternsFromIds, createTileMapLayerDescriptor, createRegionMapLayerDescriptor, } = await import('./lazy'); resolve({ - getMapsSavedObjectLoader, - getQueryableUniqueIndexPatternIds, MapEmbeddable, getIndexPatternService, - getHttp, getMapsCapabilities, - createMapStore, - addLayerWithoutDataSync, - getInitialLayers, - mergeInputWithSavedMap, renderApp, createSecurityLayerDescriptors, registerLayerWizard, registerSource, - getIndexPatternsFromIds, createTileMapLayerDescriptor, createRegionMapLayerDescriptor, }); diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts index 782d645dc230a..501b5edc2117d 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts @@ -7,18 +7,11 @@ // These are map-dependencies of the embeddable. // By lazy-loading these, the Maps-app can register the embeddable when the plugin mounts, without actually pulling all the code. -export * from '../../routing/bootstrap/services/gis_map_saved_object_loader'; export * from '../../embeddable/map_embeddable'; export * from '../../kibana_services'; -export * from '../../reducers/store'; -export * from '../../actions'; -export * from '../../selectors/map_selectors'; -export * from '../../routing/bootstrap/get_initial_layers'; -export * from '../../embeddable/merge_input_with_saved_map'; export * from '../../routing/maps_router'; export * from '../../classes/layers/solution_layers/security'; export { registerLayerWizard } from '../../classes/layers/layer_wizard_registry'; export { registerSource } from '../../classes/sources/source_registry'; -export { getIndexPatternsFromIds } from '../../index_pattern_util'; export { createTileMapLayerDescriptor } from '../../classes/layers/create_tile_map_layer_descriptor'; export { createRegionMapLayerDescriptor } from '../../classes/layers/create_region_map_layer_descriptor'; diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts new file mode 100644 index 0000000000000..01b457b8ac5f1 --- /dev/null +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -0,0 +1,71 @@ +/* + * 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 { AttributeService } from '../../../../src/plugins/embeddable/public'; +import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; +import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; +import { + MapByValueInput, + MapByReferenceInput, +} from './embeddable/types'; +import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; +import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; + + +export type MapAttributeService = AttributeService< + MapSavedObjectAttributes, + MapByValueInput, + MapByReferenceInput +>; + +export function getMapAttributeService(): MapAttributeService { + return getEmbeddableService().getAttributeService< + MapSavedObjectAttributes, + MapByValueInput, + MapByReferenceInput + >(MAP_SAVED_OBJECT_TYPE, { + saveMethod: async ( + type: string, + attributes: MapSavedObjectAttributes, + savedObjectId?: string + ) => { + throw new Error('saveMethod not implemented'); + /*const savedDoc = await savedObjectStore.save({ + ...attributes, + savedObjectId, + type: MAP_SAVED_OBJECT_TYPE, + }); + return { id: savedDoc.savedObjectId };*/ + }, + unwrapMethod: async (savedObjectId: string): Promise => { + const savedObject = await getSavedObjectsClient().get( + MAP_SAVED_OBJECT_TYPE, + savedObjectId + ); + return { + ...savedObject.attributes, + references: savedObject.references, + }; + }, + checkForDuplicateTitle: (props: OnSaveProps) => { + return checkForDuplicateTitle( + { + title: props.newTitle, + copyOnSave: false, + lastSavedTitle: '', + getEsType: () => MAP_SAVED_OBJECT_TYPE, + getDisplayName: () => MAP_SAVED_OBJECT_TYPE, + }, + props.isTitleDuplicateConfirmed, + props.onTitleDuplicate, + { + savedObjectsClient: getSavedObjectsClient(), + overlays: getCoreOverlays(), + } + ); + }, + }); +} From 1c9b361ec6738baf427e006b706862a4968eae15 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 27 Oct 2020 13:13:52 -0600 Subject: [PATCH 02/35] inject references when unwrapping --- .../embeddable/embeddable_factory.ts | 4 +- .../maps/public/embeddable/map_embeddable.tsx | 53 ++++++++++++------- .../maps/public/map_attribute_service.ts | 17 +++--- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts index aea783fce0e96..65e9c22d24eaf 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts @@ -44,9 +44,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition { getIconForSavedObject: () => 'lensApp', }; - constructor(private getStartServices: () => Promise) { - console.log(getStartServices); - } + constructor(private getStartServices: () => Promise) {} public isEditable = async () => { const { capabilities } = await this.getStartServices(); diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index fb5572673799d..c68de87eb2f9d 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -10,7 +10,12 @@ import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subscription } from 'rxjs'; import { Unsubscribe } from 'redux'; -import { Embeddable, IContainer, ReferenceOrValueEmbeddable } from '../../../../../src/plugins/embeddable/public'; +import { i18n } from '@kbn/i18n'; +import { + Embeddable, + IContainer, + ReferenceOrValueEmbeddable, +} from '../../../../../src/plugins/embeddable/public'; import { ACTION_GLOBAL_APPLY_FILTER } from '../../../../../src/plugins/data/public'; import { APPLY_FILTER_TRIGGER, @@ -50,8 +55,18 @@ import { setEventHandlers, EventHandlers, } from '../reducers/non_serializable_instances'; -import { getMapCenter, getMapZoom, getHiddenLayerIds, getQueryableUniqueIndexPatternIds } from '../selectors/map_selectors'; -import { APP_ID, getExistingMapPath, MAP_SAVED_OBJECT_TYPE, MAP_PATH } from '../../common/constants'; +import { + getMapCenter, + getMapZoom, + getHiddenLayerIds, + getQueryableUniqueIndexPatternIds, +} from '../selectors/map_selectors'; +import { + APP_ID, + getExistingMapPath, + MAP_SAVED_OBJECT_TYPE, + MAP_PATH, +} from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; @@ -59,10 +74,16 @@ import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapContainer } from '../connected_components/map_container'; import { getMapAttributeService } from '../map_attribute_service'; import { getInitialLayers } from '../routing/bootstrap/get_initial_layers'; -export { getIndexPatternsFromIds } from '../index_pattern_util'; +import { getIndexPatternsFromIds } from '../index_pattern_util'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; -import { MapByValueInput, MapByReferenceInput, MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from './types'; +import { + MapByValueInput, + MapByReferenceInput, + MapEmbeddableConfig, + MapEmbeddableInput, + MapEmbeddableOutput, +} from './types'; export { MapEmbeddableInput }; const attributeService = getMapAttributeService(); @@ -84,11 +105,7 @@ export class MapEmbeddable private _unsubscribeFromStore?: Unsubscribe; private _isInitialized = false; - constructor( - config: MapEmbeddableConfig, - initialInput: MapEmbeddableInput, - parent?: IContainer, - ) { + constructor(config: MapEmbeddableConfig, initialInput: MapEmbeddableInput, parent?: IContainer) { super( initialInput, { @@ -112,15 +129,15 @@ export class MapEmbeddable this._attributes = await attributeService.unwrapAttributes(input); const layerList = getInitialLayers(this._attributes.layerListJSON); this.setLayerList(layerList); - this.initializeOutput(); + await this.initializeOutput(); this._isInitialized = true; if (this._domNode) { this.render(this._domNode); } } - private initializeOutput() { - const savedMapTitle = this._attributes?.title ? this._attributes.title : '' + private async initializeOutput() { + const savedMapTitle = this._attributes?.title ? this._attributes.title : ''; const input = this.getInput(); const title = input.hidePanelTitles ? '' : input.title || savedMapTitle; const savedObjectId = (input as MapByReferenceInput).savedObjectId; @@ -137,7 +154,7 @@ export class MapEmbeddable input: MapByValueInput | MapByReferenceInput ): input is MapByReferenceInput { return attributeService.inputIsRefType(input); - }; + } public async getInputAsRefType(): Promise { const input = attributeService.getExplicitInputFromEmbeddable(this); @@ -145,12 +162,12 @@ export class MapEmbeddable showSaveModal: true, saveModalTitle: this.getTitle(), }); - }; + } public async getInputAsValueType(): Promise { const input = attributeService.getExplicitInputFromEmbeddable(this); return attributeService.getInputAsValueType(input); - }; + } public getDescription() { return this._attributes?.description; @@ -346,9 +363,7 @@ export class MapEmbeddable }) ); } - //console.log('getIndexPatternsFromIds', getIndexPatternsFromIds); - //const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); - //console.log('indexPatterns', indexPatterns); + const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); this.updateOutput({ ...this.getOutput(), indexPatterns: [], diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index 01b457b8ac5f1..be3693c1f1138 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -7,13 +7,11 @@ import { AttributeService } from '../../../../src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; -import { - MapByValueInput, - MapByReferenceInput, -} from './embeddable/types'; +import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; - +// @ts-expect-error +import { extractReferences, injectReferences } from '../common/migrations/references'; export type MapAttributeService = AttributeService< MapSavedObjectAttributes, @@ -33,7 +31,7 @@ export function getMapAttributeService(): MapAttributeService { savedObjectId?: string ) => { throw new Error('saveMethod not implemented'); - /*const savedDoc = await savedObjectStore.save({ + /* const savedDoc = await savedObjectStore.save({ ...attributes, savedObjectId, type: MAP_SAVED_OBJECT_TYPE, @@ -45,10 +43,9 @@ export function getMapAttributeService(): MapAttributeService { MAP_SAVED_OBJECT_TYPE, savedObjectId ); - return { - ...savedObject.attributes, - references: savedObject.references, - }; + + const { attributes } = injectReferences(savedObject); + return attributes; }, checkForDuplicateTitle: (props: OnSaveProps) => { return checkForDuplicateTitle( From 5169f9c5231cebd19aa8142e4306ae985e3e7ba1 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 27 Oct 2020 13:37:43 -0600 Subject: [PATCH 03/35] clean up map embeddable initialize --- .../maps/public/embeddable/map_embeddable.tsx | 176 +++++++++--------- 1 file changed, 89 insertions(+), 87 deletions(-) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index c68de87eb2f9d..21d8b99107be7 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -116,26 +116,104 @@ export class MapEmbeddable ); this._store = createMapStore(); - this._unsubscribeFromStore = this._store.subscribe(() => { - this._handleStoreChanges(); - }); - - this.loadMapAttributes(initialInput); - + this.initialize(initialInput); this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input)); } - private async loadMapAttributes(input: MapEmbeddableInput) { + private async initialize(input: MapEmbeddableInput) { this._attributes = await attributeService.unwrapAttributes(input); - const layerList = getInitialLayers(this._attributes.layerListJSON); - this.setLayerList(layerList); - await this.initializeOutput(); + this.initializeStore(); + this.initializeOutput(); this._isInitialized = true; if (this._domNode) { this.render(this._domNode); } } + private async initializeStore() { + this._store.dispatch(setReadOnly(true)); + this._store.dispatch(disableScrollZoom()); + + if (this._attributes?.mapStateJSON) { + const mapState = JSON.parse(this._attributes.mapStateJSON); + if (mapState.settings) { + this._store.dispatch(setMapSettings(mapState.settings)); + } + } + + let isLayerTOCOpen = DEFAULT_IS_LAYER_TOC_OPEN; + if (_.has(this.input, 'isLayerTOCOpen')) { + isLayerTOCOpen = this.input.isLayerTOCOpen; + } else if (this._attributes?.uiStateJSON) { + const uiState = JSON.parse(this._attributes.uiStateJSON); + if ('isLayerTOCOpen' in uiState) { + isLayerTOCOpen = uiState.isLayerTOCOpen; + } + } + this._store.dispatch(setIsLayerTOCOpen(isLayerTOCOpen)); + + let openTOCDetails = []; + if (_.has(this.input, 'openTOCDetails')) { + openTOCDetails = this.input.openTOCDetails; + } else if (this._attributes?.uiStateJSON) { + const uiState = JSON.parse(this._attributes.uiStateJSON); + if ('openTOCDetails' in uiState) { + openTOCDetails = uiState.openTOCDetails; + } + } + this._store.dispatch(setOpenTOCDetails(openTOCDetails)); + + if (_.has(this.input, 'disableInteractive') && this.input.disableInteractive) { + this._store.dispatch(disableInteractive()); + } + + if (_.has(this.input, 'disableTooltipControl') && this.input.disableTooltipControl) { + this._store.dispatch(disableTooltipControl()); + } + if (_.has(this.input, 'hideToolbarOverlay') && this.input.hideToolbarOverlay) { + this._store.dispatch(hideToolbarOverlay()); + } + + if (_.has(this.input, 'hideLayerControl') && this.input.hideLayerControl) { + this._store.dispatch(hideLayerControl()); + } + + if (_.has(this.input, 'hideViewControl') && this.input.hideViewControl) { + this._store.dispatch(hideViewControl()); + } + + if (this.input.mapCenter) { + this._store.dispatch( + setGotoWithCenter({ + lat: this.input.mapCenter.lat, + lon: this.input.mapCenter.lon, + zoom: this.input.mapCenter.zoom, + }) + ); + } else if (this._attributes?.mapStateJSON) { + const mapState = JSON.parse(this._attributes.mapStateJSON); + this._store.dispatch( + setGotoWithCenter({ + lat: mapState.center.lat, + lon: mapState.center.lon, + zoom: mapState.zoom, + }) + ); + } + + const layerList = getInitialLayers(this._attributes.layerListJSON); + this.setLayerList(layerList); + if (this.input.hiddenLayers) { + this._store.dispatch(setHiddenLayers(this.input.hiddenLayers)); + } + this._dispatchSetQuery(this.input); + this._dispatchSetRefreshConfig(this.input); + + this._unsubscribeFromStore = this._store.subscribe(() => { + this._handleStoreChanges(); + }); + } + private async initializeOutput() { const savedMapTitle = this._attributes?.title ? this._attributes.title : ''; const input = this.getInput(); @@ -248,82 +326,6 @@ export class MapEmbeddable return; } - this._store.dispatch(setReadOnly(true)); - this._store.dispatch(disableScrollZoom()); - - if (this._attributes?.mapStateJSON) { - const mapState = JSON.parse(this._attributes.mapStateJSON); - if (mapState.settings) { - this._store.dispatch(setMapSettings(mapState.settings)); - } - } - - let isLayerTOCOpen = DEFAULT_IS_LAYER_TOC_OPEN; - if (_.has(this.input, 'isLayerTOCOpen')) { - isLayerTOCOpen = this.input.isLayerTOCOpen; - } else if (this._attributes?.uiStateJSON) { - const uiState = JSON.parse(this._attributes.uiStateJSON); - if ('isLayerTOCOpen' in uiState) { - isLayerTOCOpen = uiState.isLayerTOCOpen; - } - } - this._store.dispatch(setIsLayerTOCOpen(isLayerTOCOpen)); - - let openTOCDetails = []; - if (_.has(this.input, 'openTOCDetails')) { - openTOCDetails = this.input.openTOCDetails; - } else if (this._attributes?.uiStateJSON) { - const uiState = JSON.parse(this._attributes.uiStateJSON); - if ('openTOCDetails' in uiState) { - openTOCDetails = uiState.openTOCDetails; - } - } - this._store.dispatch(setOpenTOCDetails(openTOCDetails)); - - if (_.has(this.input, 'disableInteractive') && this.input.disableInteractive) { - this._store.dispatch(disableInteractive()); - } - - if (_.has(this.input, 'disableTooltipControl') && this.input.disableTooltipControl) { - this._store.dispatch(disableTooltipControl()); - } - if (_.has(this.input, 'hideToolbarOverlay') && this.input.hideToolbarOverlay) { - this._store.dispatch(hideToolbarOverlay()); - } - - if (_.has(this.input, 'hideLayerControl') && this.input.hideLayerControl) { - this._store.dispatch(hideLayerControl()); - } - - if (_.has(this.input, 'hideViewControl') && this.input.hideViewControl) { - this._store.dispatch(hideViewControl()); - } - - if (this.input.mapCenter) { - this._store.dispatch( - setGotoWithCenter({ - lat: this.input.mapCenter.lat, - lon: this.input.mapCenter.lon, - zoom: this.input.mapCenter.zoom, - }) - ); - } else if (this._attributes?.mapStateJSON) { - const mapState = JSON.parse(this._attributes.mapStateJSON); - this._store.dispatch( - setGotoWithCenter({ - lat: mapState.center.lat, - lon: mapState.center.lon, - zoom: mapState.zoom, - }) - ); - } - - if (this.input.hiddenLayers) { - this._store.dispatch(setHiddenLayers(this.input.hiddenLayers)); - } - this._dispatchSetQuery(this.input); - this._dispatchSetRefreshConfig(this.input); - const I18nContext = getCoreI18n().Context; render( @@ -366,7 +368,7 @@ export class MapEmbeddable const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); this.updateOutput({ ...this.getOutput(), - indexPatterns: [], + indexPatterns, }); } From 749150310c6c78c6395593bc512d0ba4e155c48f Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 30 Oct 2020 09:25:04 -0600 Subject: [PATCH 04/35] use attribute service to load savedMap --- .../maps/public/map_attribute_service.ts | 10 +- .../maps/public/routing/render_app.tsx | 126 ++++++++++-------- .../public/routing/routes/map_app/index.ts | 100 +------------- .../public/routing/routes/map_app/map_app.tsx | 74 +++++----- .../routes/map_app/map_app_connector.ts | 103 ++++++++++++++ .../routes/map_app/map_app_container.tsx | 37 +++++ .../routing/routes/map_app/saved_map.ts | 91 +++++++++++++ 7 files changed, 349 insertions(+), 192 deletions(-) create mode 100644 x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts create mode 100644 x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx create mode 100644 x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index be3693c1f1138..db5401bf7b628 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -19,8 +19,14 @@ export type MapAttributeService = AttributeService< MapByReferenceInput >; +let mapAttributeService: MapAttributeService | null = null; + export function getMapAttributeService(): MapAttributeService { - return getEmbeddableService().getAttributeService< + if (mapAttributeService) { + return mapAttributeService; + } + + mapAttributeService = getEmbeddableService().getAttributeService< MapSavedObjectAttributes, MapByValueInput, MapByReferenceInput @@ -65,4 +71,6 @@ export function getMapAttributeService(): MapAttributeService { ); }, }); + + return mapAttributeService; } diff --git a/x-pack/plugins/maps/public/routing/render_app.tsx b/x-pack/plugins/maps/public/routing/render_app.tsx index 65cccc53f5047..9a7e828baafae 100644 --- a/x-pack/plugins/maps/public/routing/render_app.tsx +++ b/x-pack/plugins/maps/public/routing/render_app.tsx @@ -4,9 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ +import _ from 'lodash'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Router, Switch, Route, Redirect } from 'react-router-dom'; +import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; import { Provider } from 'react-redux'; import { AppMountParameters } from 'kibana/public'; @@ -22,9 +23,8 @@ import { withNotifyOnErrors, IKbnUrlStateStorage, } from '../../../../../src/plugins/kibana_utils/public'; -import { getStore } from './store_operations'; import { LoadListAndRender } from './routes/list/load_list_and_render'; -import { MapApp } from './routes/map_app'; +import { MapAppContainer, MapApp, SavedMap } from './routes/map_app'; export let goToSpecifiedPath: (path: string) => void; export let kbnUrlStateStorage: IKbnUrlStateStorage; @@ -42,16 +42,8 @@ export async function renderApp({ ...withNotifyOnErrors(getToasts()), }); - const store = getStore(); const I18nContext = getCoreI18n().Context; - const stateTransfer = getEmbeddableService()?.getStateTransfer( - history as AppMountParameters['history'] - ); - - const { originatingApp } = - stateTransfer?.getIncomingEditorState({ keysToRemoveAfterFetch: ['originatingApp'] }) || {}; - if (!getMapsCapabilities().save) { getCoreChrome().setBadge({ text: i18n.translate('xpack.maps.badge.readOnly.text', { @@ -64,53 +56,75 @@ export async function renderApp({ }); } + function renderMapApp(routeProps: RouteComponentProps<{ savedMapId?: string }>) { + const stateTransfer = getEmbeddableService()?.getStateTransfer( + history as AppMountParameters['history'] + ); + + const { originatingApp, valueInput } = + stateTransfer?.getIncomingEditorState({ keysToRemoveAfterFetch: ['originatingApp'] }) || {}; + + let mapEmbeddableInput; + if (routeProps.match.params.savedMapId) { + mapEmbeddableInput = { savedObjectId: routeProps.match.params.savedMapId }; + } + if (valueInput) { + mapEmbeddableInput = valueInput; + } + + return ( + + ); + + /* + const savedMap = new SavedMap(mapEmbeddableInput); + console.log(savedMap); + + + + return ( + + + + ) + */ + } + render( - - - - ( - - )} - /> - ( - - )} - /> - // Redirect other routes to list, or if hash-containing, their non-hash equivalents - { - if (hash) { - // Remove leading hash - const newPath = hash.substr(1); - return ; - } else if (pathname === '/' || pathname === '') { - return ; - } else { - return ; - } - }} - /> - - - + + + + + // Redirect other routes to list, or if hash-containing, their non-hash equivalents + { + if (hash) { + // Remove leading hash + const newPath = hash.substr(1); + return ; + } else if (pathname === '/' || pathname === '') { + return ; + } else { + return ; + } + }} + /> + + , element ); diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/index.ts b/x-pack/plugins/maps/public/routing/routes/map_app/index.ts index 0b9f0cfe33e44..0a56686e26314 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/index.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/index.ts @@ -4,100 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { connect } from 'react-redux'; -import { ThunkDispatch } from 'redux-thunk'; -import { AnyAction } from 'redux'; -import { Filter, Query, TimeRange } from 'src/plugins/data/public'; -import { MapApp } from './map_app'; -import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors'; -import { - getFilters, - getQuery, - getQueryableUniqueIndexPatternIds, - getRefreshConfig, - getTimeFilters, - hasDirtyState, - getLayerListConfigOnly, -} from '../../../selectors/map_selectors'; -import { - replaceLayerList, - setGotoWithCenter, - setIsLayerTOCOpen, - setMapSettings, - setOpenTOCDetails, - setQuery, - setReadOnly, - setRefreshConfig, - setSelectedLayer, - updateFlyout, - enableFullScreen, - openMapSettings, -} from '../../../actions'; -import { FLYOUT_STATE } from '../../../reducers/ui'; -import { getMapsCapabilities } from '../../../kibana_services'; -import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; -import { MapStoreState } from '../../../reducers/store'; -import { - MapRefreshConfig, - MapCenterAndZoom, - LayerDescriptor, -} from '../../../../common/descriptor_types'; -import { MapSettings } from '../../../reducers/map'; - -function mapStateToProps(state: MapStoreState) { - return { - isFullScreen: getIsFullScreen(state), - isOpenSettingsDisabled: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE, - isSaveDisabled: hasDirtyState(state), - inspectorAdapters: getInspectorAdapters(state), - nextIndexPatternIds: getQueryableUniqueIndexPatternIds(state), - flyoutDisplay: getFlyoutDisplay(state), - refreshConfig: getRefreshConfig(state), - filters: getFilters(state), - layerListConfigOnly: getLayerListConfigOnly(state), - query: getQuery(state), - timeFilters: getTimeFilters(state), - }; -} - -function mapDispatchToProps(dispatch: ThunkDispatch) { - return { - dispatchSetQuery: ({ - forceRefresh, - filters, - query, - timeFilters, - }: { - filters?: Filter[]; - query?: Query; - timeFilters?: TimeRange; - forceRefresh?: boolean; - }) => { - dispatch( - setQuery({ - filters, - query, - timeFilters, - forceRefresh, - }) - ); - }, - setRefreshConfig: (refreshConfig: MapRefreshConfig) => - dispatch(setRefreshConfig(refreshConfig)), - replaceLayerList: (layerList: LayerDescriptor[]) => dispatch(replaceLayerList(layerList)), - setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => dispatch(setGotoWithCenter(latLonZoom)), - setMapSettings: (mapSettings: MapSettings) => dispatch(setMapSettings(mapSettings)), - setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), - setOpenTOCDetails: (openTOCDetails: string[]) => dispatch(setOpenTOCDetails(openTOCDetails)), - clearUi: () => { - dispatch(setSelectedLayer(null)); - dispatch(updateFlyout(FLYOUT_STATE.NONE)); - dispatch(setReadOnly(!getMapsCapabilities().save)); - }, - enableFullScreen: () => dispatch(enableFullScreen()), - openMapSettings: () => dispatch(openMapSettings()), - }; -} - -const connectedComponent = connect(mapStateToProps, mapDispatchToProps)(MapApp); -export { connectedComponent as MapApp }; +export { MapApp } from './map_app_connector'; +export { SavedMap } from './saved_map'; +export { MapAppContainer } from './map_app_container'; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx index a7aefcad3aeda..3051305369981 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx @@ -56,9 +56,11 @@ import { MapSettings } from '../../../reducers/map'; import { ISavedGisMap } from '../../bootstrap/services/saved_gis_map'; import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; import { goToSpecifiedPath } from '../../render_app'; +import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +import { SavedMap } from './saved_map'; interface Props { - savedMapId?: string; + savedMap: SavedMap; onAppLeave: AppMountParameters['onAppLeave']; stateTransfer: EmbeddableStateTransfer; originatingApp?: string; @@ -101,7 +103,6 @@ interface State { indexPatterns: IndexPattern[]; savedQuery?: SavedQuery; originatingApp?: string; - savedMap?: ISavedGisMap; } export class MapApp extends React.Component { @@ -168,11 +169,8 @@ export class MapApp extends React.Component { } _hasUnsavedChanges = () => { - if (!this.state.savedMap) { - return false; - } - - const savedLayerList = this.state.savedMap.getLayerList(); + const attributes = this.props.savedMap.getAttributes(); + const savedLayerList = attributes.layerListJSON ? JSON.parse(attributes.layerListJSON) : null; return !savedLayerList ? !_.isEqual(this.props.layerListConfigOnly, this.state.initialLayerListConfig) : // savedMap stores layerList as a JSON string using JSON.stringify. @@ -262,12 +260,12 @@ export class MapApp extends React.Component { updateGlobalState(updatedGlobalState, !this.state.initialized); }; - _initMapAndLayerSettings(savedMap: ISavedGisMap) { + _initMapAndLayerSettings(mapSavedObjectAttributes: MapSavedObjectAttributes) { const globalState: MapsGlobalState = getGlobalState(); let savedObjectFilters = []; - if (savedMap.mapStateJSON) { - const mapState = JSON.parse(savedMap.mapStateJSON); + if (mapSavedObjectAttributes.mapStateJSON) { + const mapState = JSON.parse(mapSavedObjectAttributes.mapStateJSON); if (mapState.filters) { savedObjectFilters = mapState.filters; } @@ -275,7 +273,7 @@ export class MapApp extends React.Component { const appFilters = this._appStateManager.getFilters() || []; const query = getInitialQuery({ - mapStateJSON: savedMap.mapStateJSON, + mapStateJSON: mapSavedObjectAttributes.mapStateJSON, appState: this._appStateManager.getAppState(), }); if (query) { @@ -286,19 +284,22 @@ export class MapApp extends React.Component { filters: [..._.get(globalState, 'filters', []), ...appFilters, ...savedObjectFilters], query, time: getInitialTimeFilters({ - mapStateJSON: savedMap.mapStateJSON, + mapStateJSON: mapSavedObjectAttributes.mapStateJSON, globalState, }), }); this._onRefreshConfigChange( getInitialRefreshConfig({ - mapStateJSON: savedMap.mapStateJSON, + mapStateJSON: mapSavedObjectAttributes.mapStateJSON, globalState, }) ); - const layerList = getInitialLayers(savedMap.layerListJSON, getInitialLayersFromUrlParam()); + const layerList = getInitialLayers( + mapSavedObjectAttributes.layerListJSON, + getInitialLayersFromUrlParam() + ); this.props.replaceLayerList(layerList); this.setState({ initialLayerListConfig: copyPersistentState(layerList), @@ -348,10 +349,10 @@ export class MapApp extends React.Component { }); }; - async _loadSavedMap(): Promise { - let savedMap: ISavedGisMap | null = null; + async _initMap() { + let mapSavedObjectAttributes; try { - savedMap = await getMapsSavedObjectLoader().get(this.props.savedMapId); + mapSavedObjectAttributes = await this.props.savedMap.loadAttributes(); } catch (err) { if (this._isMounted) { getToasts().addWarning({ @@ -362,29 +363,26 @@ export class MapApp extends React.Component { }); goToSpecifiedPath('/'); } + return; } - return savedMap; - } - - async _initMap() { - const savedMap = await this._loadSavedMap(); - if (!this._isMounted || !savedMap) { + if (!this._isMounted || !mapSavedObjectAttributes) { return; } - this._setBreadcrumbs(savedMap.title); - getCoreChrome().docTitle.change(savedMap.title); - if (this.props.savedMapId) { + this._setBreadcrumbs(mapSavedObjectAttributes.title); + getCoreChrome().docTitle.change(mapSavedObjectAttributes.title); + // TODO + /* if (this.props.savedMapId) { getCoreChrome().recentlyAccessed.add(savedMap.getFullPath(), savedMap.title, savedMap.id!); - } + }*/ - this._initMapAndLayerSettings(savedMap); + this._initMapAndLayerSettings(mapSavedObjectAttributes); this.props.clearUi(); - if (savedMap.mapStateJSON) { - const mapState = JSON.parse(savedMap.mapStateJSON); + if (mapSavedObjectAttributes.mapStateJSON) { + const mapState = JSON.parse(mapSavedObjectAttributes.mapStateJSON); this.props.setGotoWithCenter({ lat: mapState.center.lat, lon: mapState.center.lon, @@ -395,22 +393,22 @@ export class MapApp extends React.Component { } } - if (savedMap.uiStateJSON) { - const uiState = JSON.parse(savedMap.uiStateJSON); + if (mapSavedObjectAttributes.uiStateJSON) { + const uiState = JSON.parse(mapSavedObjectAttributes.uiStateJSON); this.props.setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN)); this.props.setOpenTOCDetails(_.get(uiState, 'openTOCDetails', [])); } - this.setState({ initialized: true, savedMap }); + this.setState({ initialized: true }); } _renderTopNav() { - if (this.props.isFullScreen || !this.state.savedMap) { + if (this.props.isFullScreen) { return null; } const topNavConfig = getTopNavConfig({ - savedMap: this.state.savedMap, + savedMap: this.props.savedMap, isOpenSettingsDisabled: this.props.isOpenSettingsDisabled, isSaveDisabled: this.props.isSaveDisabled, enableFullScreen: this.props.enableFullScreen, @@ -485,7 +483,7 @@ export class MapApp extends React.Component { }; render() { - if (!this.state.initialized || !this.state.savedMap) { + if (!this.state.initialized) { return null; } @@ -496,8 +494,8 @@ export class MapApp extends React.Component {
diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts new file mode 100644 index 0000000000000..0b9f0cfe33e44 --- /dev/null +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts @@ -0,0 +1,103 @@ +/* + * 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 { connect } from 'react-redux'; +import { ThunkDispatch } from 'redux-thunk'; +import { AnyAction } from 'redux'; +import { Filter, Query, TimeRange } from 'src/plugins/data/public'; +import { MapApp } from './map_app'; +import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors'; +import { + getFilters, + getQuery, + getQueryableUniqueIndexPatternIds, + getRefreshConfig, + getTimeFilters, + hasDirtyState, + getLayerListConfigOnly, +} from '../../../selectors/map_selectors'; +import { + replaceLayerList, + setGotoWithCenter, + setIsLayerTOCOpen, + setMapSettings, + setOpenTOCDetails, + setQuery, + setReadOnly, + setRefreshConfig, + setSelectedLayer, + updateFlyout, + enableFullScreen, + openMapSettings, +} from '../../../actions'; +import { FLYOUT_STATE } from '../../../reducers/ui'; +import { getMapsCapabilities } from '../../../kibana_services'; +import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; +import { MapStoreState } from '../../../reducers/store'; +import { + MapRefreshConfig, + MapCenterAndZoom, + LayerDescriptor, +} from '../../../../common/descriptor_types'; +import { MapSettings } from '../../../reducers/map'; + +function mapStateToProps(state: MapStoreState) { + return { + isFullScreen: getIsFullScreen(state), + isOpenSettingsDisabled: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE, + isSaveDisabled: hasDirtyState(state), + inspectorAdapters: getInspectorAdapters(state), + nextIndexPatternIds: getQueryableUniqueIndexPatternIds(state), + flyoutDisplay: getFlyoutDisplay(state), + refreshConfig: getRefreshConfig(state), + filters: getFilters(state), + layerListConfigOnly: getLayerListConfigOnly(state), + query: getQuery(state), + timeFilters: getTimeFilters(state), + }; +} + +function mapDispatchToProps(dispatch: ThunkDispatch) { + return { + dispatchSetQuery: ({ + forceRefresh, + filters, + query, + timeFilters, + }: { + filters?: Filter[]; + query?: Query; + timeFilters?: TimeRange; + forceRefresh?: boolean; + }) => { + dispatch( + setQuery({ + filters, + query, + timeFilters, + forceRefresh, + }) + ); + }, + setRefreshConfig: (refreshConfig: MapRefreshConfig) => + dispatch(setRefreshConfig(refreshConfig)), + replaceLayerList: (layerList: LayerDescriptor[]) => dispatch(replaceLayerList(layerList)), + setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => dispatch(setGotoWithCenter(latLonZoom)), + setMapSettings: (mapSettings: MapSettings) => dispatch(setMapSettings(mapSettings)), + setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), + setOpenTOCDetails: (openTOCDetails: string[]) => dispatch(setOpenTOCDetails(openTOCDetails)), + clearUi: () => { + dispatch(setSelectedLayer(null)); + dispatch(updateFlyout(FLYOUT_STATE.NONE)); + dispatch(setReadOnly(!getMapsCapabilities().save)); + }, + enableFullScreen: () => dispatch(enableFullScreen()), + openMapSettings: () => dispatch(openMapSettings()), + }; +} + +const connectedComponent = connect(mapStateToProps, mapDispatchToProps)(MapApp); +export { connectedComponent as MapApp }; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx new file mode 100644 index 0000000000000..e79698a89617d --- /dev/null +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx @@ -0,0 +1,37 @@ +/* + * 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, { Component } from 'react'; +import { Provider } from 'react-redux'; +import { MapApp } from './map_app_connector'; +import { SavedMap } from './saved_map'; + +// react-route "render" method may be called multiple times for the same route. +// Therefore state can not exist in the "render" closure +// MapAppContainer exists to wrap MapApp in a component so that a single instance of SavedMap +// exists per route regardless of how many times render method is called. +export class MapAppContainer extends Component { + constructor(props: Props) { + super(props); + this.state = { + savedMap: new SavedMap(props.mapEmbeddableInput), + }; + } + + render() { + return ( + + + + ); + } +} diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts new file mode 100644 index 0000000000000..6b6f82fc1cf7f --- /dev/null +++ b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts @@ -0,0 +1,91 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +import { createMapStore, MapStore, MapStoreState } from '../../../reducers/store'; +import { + getTimeFilters, + getMapZoom, + getMapCenter, + getLayerListRaw, + getRefreshConfig, + getQuery, + getFilters, + getMapSettings, +} from '../../../selectors/map_selectors'; +import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; +import { copyPersistentState } from '../../../reducers/util'; +import { getMapAttributeService } from '../../../map_attribute_service'; + +export class SavedMap { + private readonly _mapEmbeddableInput?: MapEmbeddableInput; + private readonly _store: MapStore; + private _attributes: MapSavedObjectAttributes | null = null; + + constructor(mapEmbeddableInput?: MapEmbeddableInput) { + this._mapEmbeddableInput = mapEmbeddableInput; + this._store = createMapStore(); + } + + public getStore() { + return this._store; + } + + async loadAttributes() { + if (!this._mapEmbeddableInput) { + this._attributes = { + title: i18n.translate('xpack.maps.newMapTitle', { + defaultMessage: 'New Map', + }), + }; + } else { + this._attributes = await getMapAttributeService().unwrapAttributes(this._mapEmbeddableInput); + } + return this._attributes; + } + + public getAttributes(): MapSavedObjectAttributes { + if (!this._attributes) { + throw new Error('Invalid usage, must await loadAttributes before calling getAttributes'); + } + + return this._attributes; + } + + public save() { + if (!this._attributes) { + throw new Error('Invalid usage, must await loadAttributes before calling save'); + } + + this._syncAttributesWithStore(); + + const useRefType = false; + getMapAttributeService().wrapAttributes(this._attributes, useRefType); + } + + private _syncAttributesWithStore() { + const state: MapStoreState = this._store().getState(); + const layerList = getLayerListRaw(state); + const layerListConfigOnly = copyPersistentState(layerList); + this._attributes!.layerListJSON = JSON.stringify(layerListConfigOnly); + + this._attributes!.mapStateJSON = JSON.stringify({ + zoom: getMapZoom(state), + center: getMapCenter(state), + timeFilters: getTimeFilters(state), + refreshConfig: getRefreshConfig(state), + query: _.omit(getQuery(state), 'queryLastTriggeredAt'), + filters: getFilters(state), + settings: getMapSettings(state), + }); + + this._attributes!.uiStateJSON = JSON.stringify({ + isLayerTOCOpen: getIsLayerTOCOpen(state), + openTOCDetails: getOpenTOCDetails(state), + }); + } +} From 5d3e6e1a20ccc59c4d3281e117a02287adb0c0f9 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 30 Oct 2020 09:34:48 -0600 Subject: [PATCH 05/35] clean up --- .../maps/public/routing/render_app.tsx | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/x-pack/plugins/maps/public/routing/render_app.tsx b/x-pack/plugins/maps/public/routing/render_app.tsx index 9a7e828baafae..de9f0dc2fe887 100644 --- a/x-pack/plugins/maps/public/routing/render_app.tsx +++ b/x-pack/plugins/maps/public/routing/render_app.tsx @@ -9,7 +9,6 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; -import { Provider } from 'react-redux'; import { AppMountParameters } from 'kibana/public'; import { getCoreChrome, @@ -81,25 +80,6 @@ export async function renderApp({ originatingApp={originatingApp} /> ); - - /* - const savedMap = new SavedMap(mapEmbeddableInput); - console.log(savedMap); - - - - return ( - - - - ) - */ } render( From a4387e8f7e6c785962fc3a581e02aed914015b24 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 30 Oct 2020 10:50:07 -0600 Subject: [PATCH 06/35] remove clear ui since each route has its own store instance --- x-pack/plugins/maps/public/reducers/ui.ts | 4 +++- .../maps/public/routing/routes/map_app/map_app.tsx | 3 --- .../public/routing/routes/map_app/map_app_connector.ts | 8 -------- .../public/routing/routes/map_app/map_app_container.tsx | 2 +- 4 files changed, 4 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/maps/public/reducers/ui.ts b/x-pack/plugins/maps/public/reducers/ui.ts index 2ea0798d1e768..04c3805902ef6 100644 --- a/x-pack/plugins/maps/public/reducers/ui.ts +++ b/x-pack/plugins/maps/public/reducers/ui.ts @@ -5,6 +5,8 @@ */ /* eslint-disable @typescript-eslint/consistent-type-definitions */ +import { getMapsCapabilities } from '../kibana_services'; + import { UPDATE_FLYOUT, CLOSE_SET_VIEW, @@ -38,7 +40,7 @@ export const DEFAULT_IS_LAYER_TOC_OPEN = true; export const DEFAULT_MAP_UI_STATE = { flyoutDisplay: FLYOUT_STATE.NONE, isFullScreen: false, - isReadOnly: false, + isReadOnly: !getMapsCapabilities().save, isLayerTOCOpen: DEFAULT_IS_LAYER_TOC_OPEN, isSetViewOpen: false, // storing TOC detail visibility outside of map.layerList because its UI state and not map rendering state. diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx index 3051305369981..b1ea8538e0ea4 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx @@ -88,7 +88,6 @@ interface Props { refreshConfig: MapRefreshConfig; setRefreshConfig: (refreshConfig: MapRefreshConfig) => void; isSaveDisabled: boolean; - clearUi: () => void; setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => void; setMapSettings: (mapSettings: MapSettings) => void; setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => void; @@ -379,8 +378,6 @@ export class MapApp extends React.Component { this._initMapAndLayerSettings(mapSavedObjectAttributes); - this.props.clearUi(); - if (mapSavedObjectAttributes.mapStateJSON) { const mapState = JSON.parse(mapSavedObjectAttributes.mapStateJSON); this.props.setGotoWithCenter({ diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts index 0b9f0cfe33e44..1db986284825c 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts @@ -26,10 +26,7 @@ import { setMapSettings, setOpenTOCDetails, setQuery, - setReadOnly, setRefreshConfig, - setSelectedLayer, - updateFlyout, enableFullScreen, openMapSettings, } from '../../../actions'; @@ -89,11 +86,6 @@ function mapDispatchToProps(dispatch: ThunkDispatch dispatch(setMapSettings(mapSettings)), setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), setOpenTOCDetails: (openTOCDetails: string[]) => dispatch(setOpenTOCDetails(openTOCDetails)), - clearUi: () => { - dispatch(setSelectedLayer(null)); - dispatch(updateFlyout(FLYOUT_STATE.NONE)); - dispatch(setReadOnly(!getMapsCapabilities().save)); - }, enableFullScreen: () => dispatch(enableFullScreen()), openMapSettings: () => dispatch(openMapSettings()), }; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx index e79698a89617d..1dcf3e98ac955 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx @@ -9,7 +9,7 @@ import { Provider } from 'react-redux'; import { MapApp } from './map_app_connector'; import { SavedMap } from './saved_map'; -// react-route "render" method may be called multiple times for the same route. +// react-router-dom.route "render" method may be called multiple times for the same route. // Therefore state can not exist in the "render" closure // MapAppContainer exists to wrap MapApp in a component so that a single instance of SavedMap // exists per route regardless of how many times render method is called. From bff1eda00444263b1c91d853d3a00897d0ef5df5 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 2 Nov 2020 14:25:53 -0700 Subject: [PATCH 07/35] save --- x-pack/plugins/maps/common/i18n_getters.ts | 6 + x-pack/plugins/maps/kibana.json | 1 + .../embeddable/map_embeddable_factory.ts | 14 +- x-pack/plugins/maps/public/kibana_services.ts | 3 + .../maps/public/map_attribute_service.ts | 24 ++- x-pack/plugins/maps/public/plugin.ts | 2 + .../maps/public/routing/render_app.tsx | 3 +- .../public/routing/routes/map_app/map_app.tsx | 2 - .../routes/map_app/map_app_container.tsx | 14 +- .../routing/routes/map_app/saved_map.ts | 125 ++++++++++++- .../routing/routes/map_app/top_nav_config.tsx | 164 ++++++------------ 11 files changed, 226 insertions(+), 132 deletions(-) diff --git a/x-pack/plugins/maps/common/i18n_getters.ts b/x-pack/plugins/maps/common/i18n_getters.ts index 0008a119f1c7c..d0582bf5c2971 100644 --- a/x-pack/plugins/maps/common/i18n_getters.ts +++ b/x-pack/plugins/maps/common/i18n_getters.ts @@ -15,6 +15,12 @@ export function getAppTitle() { }); } +export function getMapEmbeddableTitle() { + return i18n.translate('xpack.maps.embeddableDisplayName', { + defaultMessage: 'map', + }); +} + export function getDataSourceLabel() { return i18n.translate('xpack.maps.source.dataSourceLabel', { defaultMessage: 'Data source', diff --git a/x-pack/plugins/maps/kibana.json b/x-pack/plugins/maps/kibana.json index 6f3a5b61ddc6c..74626401dd141 100644 --- a/x-pack/plugins/maps/kibana.json +++ b/x-pack/plugins/maps/kibana.json @@ -12,6 +12,7 @@ "uiActions", "navigation", "visualizations", + "dashboard", "embeddable", "mapsLegacy", "usageCollection", diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts index 836598b70dd94..7e52d033debe6 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -10,11 +10,9 @@ import { IContainer, } from '../../../../../src/plugins/embeddable/public'; import '../index.scss'; -import { - MAP_SAVED_OBJECT_TYPE, - APP_ICON, -} from '../../common/constants'; +import { MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; import { LayerDescriptor } from '../../common/descriptor_types'; +import { getMapEmbeddableTitle } from '../../common/i18n_getters'; import { MapByValueInput, MapByReferenceInput, MapEmbeddableInput } from './types'; import { lazyLoadMapModules } from '../lazy_load_bundle'; @@ -39,9 +37,7 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { } getDisplayName() { - return i18n.translate('xpack.maps.embeddableDisplayName', { - defaultMessage: 'map', - }); + return getMapEmbeddableTitle(); } createFromSavedObject = async ( @@ -59,10 +55,10 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { const { MapEmbeddable } = await lazyLoadMapModules(); return new MapEmbeddable( { - editable: await this.isEditable() + editable: await this.isEditable(), }, input, - parent, + parent ); }; } diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index 08ee4b6628dd1..6aa95b121bac9 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -74,3 +74,6 @@ export const getRegionmapLayers = () => _.get(getKibanaCommonConfig(), 'regionma export const getTilemap = () => _.get(getKibanaCommonConfig(), 'tilemap', []); export const getShareService = () => pluginsStart.share; + +export const getIsAllowByValueEmbeddables = () => + pluginsStart.dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables; diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index db5401bf7b628..9b3a7bca284e4 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -36,13 +36,25 @@ export function getMapAttributeService(): MapAttributeService { attributes: MapSavedObjectAttributes, savedObjectId?: string ) => { - throw new Error('saveMethod not implemented'); - /* const savedDoc = await savedObjectStore.save({ - ...attributes, - savedObjectId, - type: MAP_SAVED_OBJECT_TYPE, + const { attributes: attributesWithExtractedReferences, references } = extractReferences({ + attributes, }); - return { id: savedDoc.savedObjectId };*/ + + const options = { references }; + + const savedObject = await (savedObjectId + ? getSavedObjectsClient().update( + MAP_SAVED_OBJECT_TYPE, + savedObjectId, + attributesWithExtractedReferences, + options + ) + : getSavedObjectsClient().create( + MAP_SAVED_OBJECT_TYPE, + attributesWithExtractedReferences, + options + )); + return { id: savedObject.id }; }, unwrapMethod: async (savedObjectId: string): Promise => { const savedObject = await getSavedObjectsClient().get( diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index 0b797c7b8ef60..e9487ee938886 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -8,6 +8,7 @@ import { Setup as InspectorSetupContract } from 'src/plugins/inspector/public'; import { UiActionsStart } from 'src/plugins/ui_actions/public'; import { NavigationPublicPluginStart } from 'src/plugins/navigation/public'; import { Start as InspectorStartContract } from 'src/plugins/inspector/public'; +import { DashboardStart } from 'src/plugins/dashboard/public'; import { AppMountParameters, CoreSetup, @@ -73,6 +74,7 @@ export interface MapsPluginStartDependencies { uiActions: UiActionsStart; share: SharePluginStart; savedObjects: SavedObjectsStart; + dashboard: DashboardStart; } /** diff --git a/x-pack/plugins/maps/public/routing/render_app.tsx b/x-pack/plugins/maps/public/routing/render_app.tsx index de9f0dc2fe887..f20552be8dc34 100644 --- a/x-pack/plugins/maps/public/routing/render_app.tsx +++ b/x-pack/plugins/maps/public/routing/render_app.tsx @@ -60,7 +60,7 @@ export async function renderApp({ history as AppMountParameters['history'] ); - const { originatingApp, valueInput } = + const { embeddableId, originatingApp, valueInput } = stateTransfer?.getIncomingEditorState({ keysToRemoveAfterFetch: ['originatingApp'] }) || {}; let mapEmbeddableInput; @@ -74,6 +74,7 @@ export async function renderApp({ return ( void; + }) { if (!this._attributes) { throw new Error('Invalid usage, must await loadAttributes before calling save'); } + if (saveByReference) { + try { + await checkForDuplicateTitle( + { + id: newCopyOnSave ? undefined : this.getSavedObjectId(), + title: newTitle, + copyOnSave: newCopyOnSave, + lastSavedTitle: this._attributes.title, + getEsType: () => MAP_SAVED_OBJECT_TYPE, + getDisplayName: getMapEmbeddableTitle, + }, + isTitleDuplicateConfirmed, + onTitleDuplicate, + { + savedObjectsClient: getSavedObjectsClient(), + overlays: getCoreOverlays(), + } + ); + } catch (e) { + // ignore duplicate title failure, user notified in save modal + return; + } + } + + const prevTitle = this._attributes.title; + const prevDescription = this._attributes.description; + this._attributes.title = newTitle; + this._attributes.description = newDescription; this._syncAttributesWithStore(); - const useRefType = false; - getMapAttributeService().wrapAttributes(this._attributes, useRefType); + let updatedMapEmbeddableInput: MapEmbeddableInput; + try { + updatedMapEmbeddableInput = await getMapAttributeService().wrapAttributes( + this._attributes, + saveByReference, + newCopyOnSave ? undefined : this._mapEmbeddableInput + ); + } catch (e) { + // Error toast displayed by wrapAttributes + this._attributes.title = prevTitle; + this._attributes.description = prevDescription; + return; + } + + if (returnToOrigin) { + if (!originatingApp) { + getToasts().addDanger({ + title: i18n.translate('xpack.maps.topNav.saveErrorMessage', { + defaultMessage: `Error saving '{title}'`, + values: { title: newTitle }, + }), + text: i18n.translate('xpack.maps.topNav.saveErrorMessage', { + defaultMessage: 'Unable to return to app without an originating app', + }), + }); + return; + } + stateTransfer.navigateToWithEmbeddablePackage(originatingApp, { + state: { + embeddableId: newCopyOnSave ? undefined : this._embeddableId, + type: MAP_SAVED_OBJECT_TYPE, + updatedMapEmbeddableInput, + }, + }); + return; + } + + getToasts().addSuccess({ + title: i18n.translate('xpack.maps.topNav.saveSuccessMessage', { + defaultMessage: `Saved '{title}'`, + values: { title: newTitle }, + }), + }); + + getCoreChrome().docTitle.change(newTitle); + setBreadcrumbs(newTitle); + goToSpecifiedPath(`/map/${updatedMapEmbeddableInput.savedObjectId}${window.location.hash}`); + return { id: updatedMapEmbeddableInput.savedObjectId }; } private _syncAttributesWithStore() { - const state: MapStoreState = this._store().getState(); + const state: MapStoreState = this._store.getState(); const layerList = getLayerListRaw(state); const layerListConfigOnly = copyPersistentState(layerList); this._attributes!.layerListJSON = JSON.stringify(layerListConfigOnly); diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx index c60f44093541f..7d8989cfdc76f 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx @@ -14,6 +14,7 @@ import { getToasts, getCoreI18n, getNavigateToApp, + getIsAllowByValueEmbeddables, } from '../../../kibana_services'; import { SavedObjectSaveModalOrigin, @@ -22,9 +23,19 @@ import { } from '../../../../../../../src/plugins/saved_objects/public'; import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; import { goToSpecifiedPath } from '../../render_app'; -import { ISavedGisMap } from '../../bootstrap/services/saved_gis_map'; +import { SavedMap } from './saved_map'; import { EmbeddableStateTransfer } from '../../../../../../../src/plugins/embeddable/public'; +function getSaveAndReturnButtonLabel() { + return getIsAllowByValueEmbeddables() + ? i18n.translate('xpack.maps.topNav.saveToMaps', { + defaultMessage: 'Save to Maps', + }) + : i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { + defaultMessage: 'Save as', + }); +} + export function getTopNavConfig({ savedMap, isOpenSettingsDisabled, @@ -35,9 +46,8 @@ export function getTopNavConfig({ setBreadcrumbs, stateTransfer, originatingApp, - cutOriginatingAppConnection, }: { - savedMap: ISavedGisMap; + savedMap: SavedMap; isOpenSettingsDisabled: boolean; isSaveDisabled: boolean; enableFullScreen: () => void; @@ -45,83 +55,8 @@ export function getTopNavConfig({ inspectorAdapters: Adapters; setBreadcrumbs: (title: string) => void; stateTransfer?: EmbeddableStateTransfer; - originatingApp?: string; - cutOriginatingAppConnection: () => void; }) { const topNavConfigs = []; - const isNewMap = !savedMap.id; - const hasWritePermissions = getMapsCapabilities().save; - const hasSaveAndReturnConfig = hasWritePermissions && !isNewMap && originatingApp; - - async function onSave({ - newDescription, - newTitle, - newCopyOnSave, - isTitleDuplicateConfirmed, - onTitleDuplicate, - returnToOrigin, - }: OnSaveProps & { returnToOrigin: boolean }) { - const prevTitle = savedMap.title; - const prevDescription = savedMap.description; - savedMap.title = newTitle; - savedMap.description = newDescription; - savedMap.copyOnSave = newCopyOnSave; - - let savedObjectId; - try { - savedMap.syncWithStore(); - savedObjectId = await savedMap.save({ - confirmOverwrite: false, - isTitleDuplicateConfirmed, - onTitleDuplicate, - }); - // id not returned when save fails because of duplicate title check. - // return and let user confirm duplicate title. - if (!savedObjectId) { - return {}; - } - } catch (err) { - getToasts().addDanger({ - title: i18n.translate('xpack.maps.topNav.saveErrorMessage', { - defaultMessage: `Error saving '{title}'`, - values: { title: savedMap.title }, - }), - text: err.message, - 'data-test-subj': 'saveMapError', - }); - // If the save wasn't successful, put the original values back. - savedMap.title = prevTitle; - savedMap.description = prevDescription; - return { error: err }; - } - - getToasts().addSuccess({ - title: i18n.translate('xpack.maps.topNav.saveSuccessMessage', { - defaultMessage: `Saved '{title}'`, - values: { title: savedMap.title }, - }), - 'data-test-subj': 'saveMapSuccess', - }); - - getCoreChrome().docTitle.change(savedMap.title); - setBreadcrumbs(savedMap.title); - goToSpecifiedPath(`/map/${savedObjectId}${window.location.hash}`); - - const newlyCreated = newCopyOnSave || isNewMap; - if (newlyCreated && !returnToOrigin) { - cutOriginatingAppConnection(); - } else if (!!originatingApp && returnToOrigin) { - if (newlyCreated && stateTransfer) { - stateTransfer.navigateToWithEmbeddablePackage(originatingApp, { - state: { input: { savedObjectId }, type: MAP_SAVED_OBJECT_TYPE }, - }); - } else { - getNavigateToApp()(originatingApp); - } - } - - return { id: savedObjectId }; - } topNavConfigs.push( { @@ -169,14 +104,15 @@ export function getTopNavConfig({ } ); - if (hasWritePermissions) { + if (getMapsCapabilities().save) { + const hasSaveAndReturnConfig = originatingApp; + const mapSavedObjectAttributes = savedMap.getAttributes(); + topNavConfigs.push({ id: 'save', iconType: hasSaveAndReturnConfig ? undefined : 'save', label: hasSaveAndReturnConfig - ? i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { - defaultMessage: 'Save as', - }) + ? getSaveAndReturnButtonLabel() : i18n.translate('xpack.maps.topNav.saveMapButtonLabel', { defaultMessage: `save`, }), @@ -200,12 +136,20 @@ export function getTopNavConfig({ { + return savedMap.save({ + ...props, + saveByReference: true, + originatingApp, + stateTransfer, + setBreadcrumbs, + }); + }} onClose={() => {}} documentInfo={{ - description: savedMap.description, - id: savedMap.id, - title: savedMap.title, + description: mapSavedObjectAttributes.description, + id: savedMap.getSavedObjectId(), + title: mapSavedObjectAttributes.title, }} objectType={i18n.translate('xpack.maps.topNav.saveModalType', { defaultMessage: 'map', @@ -215,28 +159,34 @@ export function getTopNavConfig({ showSaveModal(saveModal, getCoreI18n().Context); }, }); - } - if (hasSaveAndReturnConfig) { - topNavConfigs.push({ - id: 'saveAndReturn', - label: i18n.translate('xpack.maps.topNav.saveAndReturnButtonLabel', { - defaultMessage: 'Save and return', - }), - emphasize: true, - iconType: 'checkInCircleFilled', - run: () => { - onSave({ - newTitle: savedMap.title ? savedMap.title : '', - newDescription: savedMap.description ? savedMap.description : '', - newCopyOnSave: false, - isTitleDuplicateConfirmed: false, - returnToOrigin: true, - onTitleDuplicate: () => {}, - }); - }, - testId: 'mapSaveAndReturnButton', - }); + if (hasSaveAndReturnConfig) { + topNavConfigs.push({ + id: 'saveAndReturn', + label: i18n.translate('xpack.maps.topNav.saveAndReturnButtonLabel', { + defaultMessage: 'Save and return', + }), + emphasize: true, + iconType: 'checkInCircleFilled', + run: () => { + return savedMap.save({ + newTitle: mapSavedObjectAttributes.title ? mapSavedObjectAttributes.title : '', + newDescription: mapSavedObjectAttributes.description + ? mapSavedObjectAttributes.description + : '', + newCopyOnSave: false, + isTitleDuplicateConfirmed: false, + returnToOrigin: true, + onTitleDuplicate: () => {}, + saveByReference: false, + originatingApp, + stateTransfer, + setBreadcrumbs, + }); + }, + testId: 'mapSaveAndReturnButton', + }); + } } return topNavConfigs; From aca8f6e483d0be3d0a0a6a4dbef8864e9dffe550 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 2 Nov 2020 16:25:55 -0700 Subject: [PATCH 08/35] update for API changes --- x-pack/plugins/maps/public/map_attribute_service.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index 9b3a7bca284e4..63dcdc8ad46fa 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -31,28 +31,22 @@ export function getMapAttributeService(): MapAttributeService { MapByValueInput, MapByReferenceInput >(MAP_SAVED_OBJECT_TYPE, { - saveMethod: async ( - type: string, - attributes: MapSavedObjectAttributes, - savedObjectId?: string - ) => { + saveMethod: async (attributes: MapSavedObjectAttributes, savedObjectId?: string) => { const { attributes: attributesWithExtractedReferences, references } = extractReferences({ attributes, }); - const options = { references }; - const savedObject = await (savedObjectId ? getSavedObjectsClient().update( MAP_SAVED_OBJECT_TYPE, savedObjectId, attributesWithExtractedReferences, - options + { references } ) : getSavedObjectsClient().create( MAP_SAVED_OBJECT_TYPE, attributesWithExtractedReferences, - options + { references } )); return { id: savedObject.id }; }, From aa1642e5a255efe25a3fb439c4afc5c353881886 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 08:52:37 -0700 Subject: [PATCH 09/35] pass input to stateTransfer --- x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts index 075f8f60653b6..cdabbfd4f4743 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts @@ -161,7 +161,7 @@ export class SavedMap { state: { embeddableId: newCopyOnSave ? undefined : this._embeddableId, type: MAP_SAVED_OBJECT_TYPE, - updatedMapEmbeddableInput, + input: updatedMapEmbeddableInput, }, }); return; From 41294ca5f149fe0ca4325f9adbd1142ba9e0b376 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 12:33:12 -0700 Subject: [PATCH 10/35] remove map saved object loader --- .../services/gis_map_saved_object_loader.ts | 16 --- .../bootstrap/services/saved_gis_map.ts | 121 ------------------ .../routes/list/load_list_and_render.tsx | 11 +- .../routing/routes/list/maps_list_view.tsx | 38 ++++-- 4 files changed, 35 insertions(+), 151 deletions(-) delete mode 100644 x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts delete mode 100644 x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts diff --git a/x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts b/x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts deleted file mode 100644 index fe8aa02615b85..0000000000000 --- a/x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts +++ /dev/null @@ -1,16 +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 _ from 'lodash'; -import { createSavedGisMapClass } from './saved_gis_map'; -import { SavedObjectLoader } from '../../../../../../../src/plugins/saved_objects/public'; -import { getSavedObjects, getSavedObjectsClient } from '../../../kibana_services'; - -export const getMapsSavedObjectLoader = _.once(function () { - const SavedGisMap = createSavedGisMapClass(getSavedObjects()); - - return new SavedObjectLoader(SavedGisMap, getSavedObjectsClient()); -}); diff --git a/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts b/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts deleted file mode 100644 index 7b31d9edea90d..0000000000000 --- a/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts +++ /dev/null @@ -1,121 +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 _ from 'lodash'; -import { SavedObjectReference } from 'kibana/public'; -import { i18n } from '@kbn/i18n'; -import { - SavedObjectsStart, - SavedObject, -} from '../../../../../../../src/plugins/saved_objects/public'; -import { - getTimeFilters, - getMapZoom, - getMapCenter, - getLayerListRaw, - getRefreshConfig, - getQuery, - getFilters, - getMapSettings, -} from '../../../selectors/map_selectors'; -import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; -import { copyPersistentState } from '../../../reducers/util'; -// @ts-expect-error -import { extractReferences, injectReferences } from '../../../../common/migrations/references'; -import { getExistingMapPath, MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -import { getStore } from '../../store_operations'; -import { MapStoreState } from '../../../reducers/store'; -import { LayerDescriptor } from '../../../../common/descriptor_types'; - -export interface ISavedGisMap extends SavedObject { - layerListJSON?: string; - mapStateJSON?: string; - uiStateJSON?: string; - description?: string; - getLayerList(): LayerDescriptor[]; - syncWithStore(): void; -} - -export function createSavedGisMapClass(savedObjects: SavedObjectsStart) { - class SavedGisMap extends savedObjects.SavedObjectClass implements ISavedGisMap { - public static type = MAP_SAVED_OBJECT_TYPE; - - // Mappings are used to place object properties into saved object _source - public static mapping = { - title: 'text', - description: 'text', - mapStateJSON: 'text', - layerListJSON: 'text', - uiStateJSON: 'text', - }; - public static fieldOrder = ['title', 'description']; - public static searchSource = false; - - public showInRecentlyAccessed = true; - public layerListJSON?: string; - public mapStateJSON?: string; - public uiStateJSON?: string; - - constructor(id: string) { - super({ - type: SavedGisMap.type, - mapping: SavedGisMap.mapping, - searchSource: SavedGisMap.searchSource, - extractReferences, - injectReferences: (savedObject: ISavedGisMap, references: SavedObjectReference[]) => { - const { attributes } = injectReferences({ - attributes: { layerListJSON: savedObject.layerListJSON }, - references, - }); - - savedObject.layerListJSON = attributes.layerListJSON; - }, - - // if this is null/undefined then the SavedObject will be assigned the defaults - id, - - // default values that will get assigned if the doc is new - defaults: { - title: i18n.translate('xpack.maps.newMapTitle', { - defaultMessage: 'New Map', - }), - description: '', - }, - }); - - this.getFullPath = () => { - return getExistingMapPath(this.id!); - }; - } - - getLayerList() { - return this.layerListJSON ? JSON.parse(this.layerListJSON) : null; - } - - syncWithStore() { - const state: MapStoreState = getStore().getState(); - const layerList = getLayerListRaw(state); - const layerListConfigOnly = copyPersistentState(layerList); - this.layerListJSON = JSON.stringify(layerListConfigOnly); - - this.mapStateJSON = JSON.stringify({ - zoom: getMapZoom(state), - center: getMapCenter(state), - timeFilters: getTimeFilters(state), - refreshConfig: getRefreshConfig(state), - query: _.omit(getQuery(state), 'queryLastTriggeredAt'), - filters: getFilters(state), - settings: getMapSettings(state), - }); - - this.uiStateJSON = JSON.stringify({ - isLayerTOCOpen: getIsLayerTOCOpen(state), - openTOCDetails: getOpenTOCDetails(state), - }); - } - } - return SavedGisMap; -} diff --git a/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx b/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx index e85afb470dbe6..1db60604af539 100644 --- a/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx +++ b/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx @@ -8,8 +8,9 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { Redirect } from 'react-router-dom'; import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; -import { getToasts } from '../../../kibana_services'; +import { getSavedObjectsClient, getToasts } from '../../../kibana_services'; import { MapsListView } from './maps_list_view'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; export class LoadListAndRender extends React.Component { _isMounted: boolean = false; @@ -29,9 +30,13 @@ export class LoadListAndRender extends React.Component { async _loadMapsList() { try { - const { hits = [] } = await getMapsSavedObjectLoader().find('', 1); + const results = await getSavedObjectsClient().find({ + type: MAP_SAVED_OBJECT_TYPE, + perPage: 1, + fields: ['title'], + }); if (this._isMounted) { - this.setState({ mapsLoaded: true, hasSavedMaps: !!hits.length }); + this.setState({ mapsLoaded: true, hasSavedMaps: !!results.savedObjects.length }); } } catch (err) { if (this._isMounted) { diff --git a/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx b/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx index ca92442ae93e6..6cf7bed62fa7d 100644 --- a/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx @@ -33,16 +33,17 @@ import { EuiTableSortingType } from '@elastic/eui'; import { goToSpecifiedPath } from '../../render_app'; // @ts-expect-error import { addHelpMenuToAppChrome } from '../../../help_menu_util'; -import { APP_ID, MAP_PATH } from '../../../../common/constants'; +import { APP_ID, MAP_PATH, MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; import { getMapsCapabilities, getUiSettings, getToasts, getCoreChrome, getNavigateToApp, + getSavedObjectsClient, } from '../../../kibana_services'; -import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; import { getAppTitle } from '../../../../common/i18n_getters'; +import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; export const EMPTY_FILTER = ''; @@ -60,7 +61,7 @@ interface State { showDeleteModal: boolean; showLimitError: boolean; filter: string; - items: SelectionItem[]; + items: TableRow[]; selectedIds: string[]; page: number; perPage: number; @@ -69,8 +70,10 @@ interface State { totalItems?: number; } -interface SelectionItem { +interface TableRow { id: string; + title: string; + description?: string; } export class MapsListView extends React.Component { @@ -106,12 +109,16 @@ export class MapsListView extends React.Component { getCoreChrome().setBreadcrumbs([{ text: getAppTitle() }]); } - _find = (search: string) => getMapsSavedObjectLoader().find(search, this.state.listingLimit); - - _delete = (ids: string[]) => getMapsSavedObjectLoader().delete(ids); - debouncedFetch = _.debounce(async (filter) => { - const response = await this._find(filter); + const response = await getSavedObjectsClient().find({ + type: MAP_SAVED_OBJECT_TYPE, + search: filter ? `${filter}*` : undefined, + perPage: this.state.listingLimit, + page: 1, + searchFields: ['title^3', 'description'], + defaultSearchOperator: 'AND', + fields: ['description', 'title'], + }); if (!this._isMounted) { return; @@ -123,7 +130,13 @@ export class MapsListView extends React.Component { this.setState({ hasInitialFetchReturned: true, isFetchingItems: false, - items: response.hits, + items: response.savedObjects.map((savedObject) => { + return { + id: savedObject.id, + title: savedObject.attributes.title, + description: savedObject.attributes.description, + }; + }), totalItems: response.total, showLimitError: response.total > this.state.listingLimit, }); @@ -141,7 +154,10 @@ export class MapsListView extends React.Component { deleteSelectedItems = async () => { try { - await this._delete(this.state.selectedIds); + const deletions = this.state.selectedIds.map((id) => { + return getSavedObjectsClient().delete(MAP_SAVED_OBJECT_TYPE, id); + }); + await Promise.all(deletions); } catch (error) { getToasts().addDanger({ title: i18n.translate('xpack.maps.mapListing.unableToDeleteToastTitle', { From b7bf3bed23364d4f5059709392cf03cc6d49ce8b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 12:42:48 -0700 Subject: [PATCH 11/35] remove unused store_operations --- .../plugins/maps/public/routing/store_operations.ts | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 x-pack/plugins/maps/public/routing/store_operations.ts diff --git a/x-pack/plugins/maps/public/routing/store_operations.ts b/x-pack/plugins/maps/public/routing/store_operations.ts deleted file mode 100644 index 53ebbb3328ff9..0000000000000 --- a/x-pack/plugins/maps/public/routing/store_operations.ts +++ /dev/null @@ -1,11 +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 { createMapStore } from '../reducers/store'; - -const store = createMapStore(); - -export const getStore = () => store; From eec85fd983766ff102caab4120e5c58737be8481 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 12:56:27 -0700 Subject: [PATCH 12/35] add saved objects to recently accessed --- .../maps/public/routing/routes/map_app/map_app.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx index 4fcc6ffb5e0b4..94a4c5607b9ae 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx @@ -55,6 +55,7 @@ import { import { MapSettings } from '../../../reducers/map'; import { goToSpecifiedPath } from '../../render_app'; import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +import { getExistingMapPath } from '../../../../common/constants'; import { SavedMap } from './saved_map'; interface Props { @@ -369,10 +370,14 @@ export class MapApp extends React.Component { this._setBreadcrumbs(mapSavedObjectAttributes.title); getCoreChrome().docTitle.change(mapSavedObjectAttributes.title); - // TODO - /* if (this.props.savedMapId) { - getCoreChrome().recentlyAccessed.add(savedMap.getFullPath(), savedMap.title, savedMap.id!); - }*/ + const savedObjectId = this.props.savedMap.getSavedObjectId(); + if (savedObjectId) { + getCoreChrome().recentlyAccessed.add( + getExistingMapPath(savedObjectId), + mapSavedObjectAttributes.title, + savedObjectId + ); + } this._initMapAndLayerSettings(mapSavedObjectAttributes); From 37e3372fa40e1eb656233c7011c6f65b7d48658e Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 12:58:11 -0700 Subject: [PATCH 13/35] provide default description --- x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts index cdabbfd4f4743..5b44dec4923ec 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts @@ -59,6 +59,7 @@ export class SavedMap { title: i18n.translate('xpack.maps.newMapTitle', { defaultMessage: 'New Map', }), + description: '', }; } else { this._attributes = await getMapAttributeService().unwrapAttributes(this._mapEmbeddableInput); From 5e21aecfc057655a022b2ca8c92aea176164156f Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 3 Nov 2020 15:25:59 -0700 Subject: [PATCH 14/35] break originatingApp connection when not returnToOrigin --- .../public/routing/routes/map_app/map_app.tsx | 78 +---------- .../routes/map_app/map_app_connector.ts | 19 +-- .../routes/map_app/map_app_container.tsx | 12 +- .../routing/routes/map_app/saved_map.ts | 123 ++++++++++++++++-- .../routing/routes/map_app/top_nav_config.tsx | 28 ++-- 5 files changed, 134 insertions(+), 126 deletions(-) diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx index 94a4c5607b9ae..3020db1a50cef 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx @@ -11,7 +11,6 @@ import { i18n } from '@kbn/i18n'; import { AppLeaveAction, AppMountParameters } from 'kibana/public'; import { EmbeddableStateTransfer, Adapters } from 'src/plugins/embeddable/public'; import { Subscription } from 'rxjs'; -import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; import { getData, getCoreChrome, @@ -19,8 +18,6 @@ import { getNavigation, getToasts, } from '../../../kibana_services'; -import { copyPersistentState } from '../../../reducers/util'; -import { getInitialLayers, getInitialLayersFromUrlParam } from '../../bootstrap/get_initial_layers'; import { getInitialTimeFilters } from '../../bootstrap/get_initial_time_filters'; import { getInitialRefreshConfig } from '../../bootstrap/get_initial_refresh_config'; import { getInitialQuery } from '../../bootstrap/get_initial_query'; @@ -61,10 +58,7 @@ import { SavedMap } from './saved_map'; interface Props { savedMap: SavedMap; onAppLeave: AppMountParameters['onAppLeave']; - stateTransfer: EmbeddableStateTransfer; - originatingApp?: string; layerListConfigOnly: LayerDescriptor[]; - replaceLayerList: (layerList: LayerDescriptor[]) => void; filters: Filter[]; isFullScreen: boolean; isOpenSettingsDisabled: boolean; @@ -87,20 +81,14 @@ interface Props { refreshConfig: MapRefreshConfig; setRefreshConfig: (refreshConfig: MapRefreshConfig) => void; isSaveDisabled: boolean; - setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => void; - setMapSettings: (mapSettings: MapSettings) => void; - setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => void; - setOpenTOCDetails: (openTOCDetails: string[]) => void; query: MapQuery | undefined; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; } interface State { initialized: boolean; - initialLayerListConfig?: LayerDescriptor[]; indexPatterns: IndexPattern[]; savedQuery?: SavedQuery; - originatingApp?: string; } export class MapApp extends React.Component { @@ -116,8 +104,6 @@ export class MapApp extends React.Component { this.state = { indexPatterns: [], initialized: false, - // tracking originatingApp in state so the connection can be broken by users - originatingApp: props.originatingApp, }; } @@ -139,7 +125,7 @@ export class MapApp extends React.Component { this._initMap(); this.props.onAppLeave((actions) => { - if (this._hasUnsavedChanges()) { + if (this.props.savedMap.hasUnsavedChanges()) { return actions.confirm(unsavedChangesWarning, unsavedChangesTitle); } return actions.default() as AppLeaveAction; @@ -163,31 +149,10 @@ export class MapApp extends React.Component { this._globalSyncChangeMonitorSubscription.unsubscribe(); } - getCoreChrome().setBreadcrumbs([]); - } - - _hasUnsavedChanges = () => { - const attributes = this.props.savedMap.getAttributes(); - const savedLayerList = attributes.layerListJSON ? JSON.parse(attributes.layerListJSON) : null; - 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 = (title: string) => { - const breadcrumbs = getBreadcrumbs({ - title, - getHasUnsavedChanges: this._hasUnsavedChanges, - originatingApp: this.state.originatingApp, - getAppNameFromId: this.props.stateTransfer.getAppNameFromId, + this.props.onAppLeave((actions) => { + return actions.default(); }); - getCoreChrome().setBreadcrumbs(breadcrumbs); - }; + } _updateFromGlobalState = ({ changes, @@ -293,15 +258,6 @@ export class MapApp extends React.Component { globalState, }) ); - - const layerList = getInitialLayers( - mapSavedObjectAttributes.layerListJSON, - getInitialLayersFromUrlParam() - ); - this.props.replaceLayerList(layerList); - this.setState({ - initialLayerListConfig: copyPersistentState(layerList), - }); } _onFiltersChange = (filters: Filter[]) => { @@ -368,7 +324,7 @@ export class MapApp extends React.Component { return; } - this._setBreadcrumbs(mapSavedObjectAttributes.title); + this.props.savedMap.setBreadcrumbs(); getCoreChrome().docTitle.change(mapSavedObjectAttributes.title); const savedObjectId = this.props.savedMap.getSavedObjectId(); if (savedObjectId) { @@ -381,24 +337,6 @@ export class MapApp extends React.Component { this._initMapAndLayerSettings(mapSavedObjectAttributes); - if (mapSavedObjectAttributes.mapStateJSON) { - const mapState = JSON.parse(mapSavedObjectAttributes.mapStateJSON); - this.props.setGotoWithCenter({ - lat: mapState.center.lat, - lon: mapState.center.lon, - zoom: mapState.zoom, - }); - if (mapState.settings) { - this.props.setMapSettings(mapState.settings); - } - } - - if (mapSavedObjectAttributes.uiStateJSON) { - const uiState = JSON.parse(mapSavedObjectAttributes.uiStateJSON); - this.props.setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN)); - this.props.setOpenTOCDetails(_.get(uiState, 'openTOCDetails', [])); - } - this.setState({ initialized: true }); } @@ -414,12 +352,6 @@ export class MapApp extends React.Component { enableFullScreen: this.props.enableFullScreen, openMapSettings: this.props.openMapSettings, inspectorAdapters: this.props.inspectorAdapters, - setBreadcrumbs: this._setBreadcrumbs, - stateTransfer: this.props.stateTransfer, - originatingApp: this.state.originatingApp, - cutOriginatingAppConnection: () => { - this.setState({ originatingApp: undefined }); - }, }); const { TopNavMenu } = getNavigation().ui; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts index 1db986284825c..1d8423578b54a 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts @@ -17,19 +17,8 @@ import { getRefreshConfig, getTimeFilters, hasDirtyState, - getLayerListConfigOnly, } from '../../../selectors/map_selectors'; -import { - replaceLayerList, - setGotoWithCenter, - setIsLayerTOCOpen, - setMapSettings, - setOpenTOCDetails, - setQuery, - setRefreshConfig, - enableFullScreen, - openMapSettings, -} from '../../../actions'; +import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../../actions'; import { FLYOUT_STATE } from '../../../reducers/ui'; import { getMapsCapabilities } from '../../../kibana_services'; import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; @@ -51,7 +40,6 @@ function mapStateToProps(state: MapStoreState) { flyoutDisplay: getFlyoutDisplay(state), refreshConfig: getRefreshConfig(state), filters: getFilters(state), - layerListConfigOnly: getLayerListConfigOnly(state), query: getQuery(state), timeFilters: getTimeFilters(state), }; @@ -81,11 +69,6 @@ function mapDispatchToProps(dispatch: ThunkDispatch dispatch(setRefreshConfig(refreshConfig)), - replaceLayerList: (layerList: LayerDescriptor[]) => dispatch(replaceLayerList(layerList)), - setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => dispatch(setGotoWithCenter(latLonZoom)), - setMapSettings: (mapSettings: MapSettings) => dispatch(setMapSettings(mapSettings)), - setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), - setOpenTOCDetails: (openTOCDetails: string[]) => dispatch(setOpenTOCDetails(openTOCDetails)), enableFullScreen: () => dispatch(enableFullScreen()), openMapSettings: () => dispatch(openMapSettings()), }; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx index 9399a6b009ba8..1f0f7ba1a9e63 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx @@ -7,7 +7,7 @@ import React, { Component } from 'react'; import { Provider } from 'react-redux'; import { AppMountParameters } from 'kibana/public'; -import { EmbeddableStateTransfer, Adapters } from 'src/plugins/embeddable/public'; +import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapApp } from './map_app_connector'; import { SavedMap } from './saved_map'; import { MapEmbeddableInput } from '../../../embeddable/types'; @@ -29,7 +29,12 @@ export class MapAppContainer extends Component { constructor(props: Props) { super(props); this.state = { - savedMap: new SavedMap(props.mapEmbeddableInput, this.props.embeddableId), + savedMap: new SavedMap({ + mapEmbeddableInput: props.mapEmbeddableInput, + embeddableId: this.props.embeddableId, + originatingApp: this.props.originatingApp, + stateTransfer: this.props.stateTransfer, + }), }; } @@ -40,8 +45,7 @@ export class MapAppContainer extends Component { savedMap={this.state.savedMap} onAppLeave={this.props.onAppLeave} setHeaderActionMenu={this.props.setHeaderActionMenu} - stateTransfer={this.props.stateTransfer} - originatingApp={this.props.originatingApp} + getAppNameFromId={this.props.stateTransfer.getAppNameFromId} /> ); diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts index 5b44dec4923ec..7a60b9d4265ea 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts +++ b/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts @@ -19,9 +19,16 @@ import { getQuery, getFilters, getMapSettings, + getLayerListConfigOnly, } from '../../../selectors/map_selectors'; +import { + setGotoWithCenter, + setMapSettings, + replaceLayerList, + setIsLayerTOCOpen, + setOpenTOCDetails, +} from '../../../actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; -import { copyPersistentState } from '../../../reducers/util'; import { getMapAttributeService } from '../../../map_attribute_service'; import { checkForDuplicateTitle, @@ -35,17 +42,36 @@ import { getToasts, } from '../../../kibana_services'; import { goToSpecifiedPath } from '../../render_app'; +import { LayerDescriptor } from '../../../../common/descriptor_types'; +import { getInitialLayers, getInitialLayersFromUrlParam } from '../../bootstrap/get_initial_layers'; +import { copyPersistentState } from '../../../reducers/util'; +import { getBreadcrumbs } from './get_breadcrumbs'; +import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; export class SavedMap { private _attributes: MapSavedObjectAttributes | null = null; private readonly _embeddableId?: string; + private _initialLayerListConfig: LayerDescriptor[] = []; private readonly _mapEmbeddableInput?: MapEmbeddableInput; private _originatingApp?: string; + private readonly _stateTransfer: EmbeddableStateTransfer; private readonly _store: MapStore; - constructor(mapEmbeddableInput?: MapEmbeddableInput, embeddableId?: string) { + constructor({ + mapEmbeddableInput, + embeddableId, + originatingApp, + stateTransfer, + }: { + mapEmbeddableInput?: MapEmbeddableInput; + embeddableId?: string; + originatingApp?: string; + stateTransfer: EmbeddableStateTransfer; + }) { this._mapEmbeddableInput = mapEmbeddableInput; this._embeddableId = embeddableId; + this._originatingApp = originatingApp; + this._stateTransfer = stateTransfer; this._store = createMapStore(); } @@ -57,20 +83,95 @@ export class SavedMap { if (!this._mapEmbeddableInput) { this._attributes = { title: i18n.translate('xpack.maps.newMapTitle', { - defaultMessage: 'New Map', + defaultMessage: 'New map', }), description: '', }; } else { this._attributes = await getMapAttributeService().unwrapAttributes(this._mapEmbeddableInput); } + + const layerList = getInitialLayers( + this._attributes.layerListJSON, + getInitialLayersFromUrlParam() + ); + this._store.dispatch(replaceLayerList(layerList)); + this._initialLayerListConfig = copyPersistentState(layerList); + + if (this._attributes.mapStateJSON) { + const mapState = JSON.parse(this._attributes.mapStateJSON); + this._store.dispatch( + setGotoWithCenter({ + lat: mapState.center.lat, + lon: mapState.center.lon, + zoom: mapState.zoom, + }) + ); + if (mapState.settings) { + this._store.dispatch(setMapSettings(mapState.settings)); + } + } + + if (this._attributes.uiStateJSON) { + const uiState = JSON.parse(this._attributes.uiStateJSON); + this._store.dispatch( + setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN)) + ); + this._store.dispatch(setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []))); + } + return this._attributes; } + hasUnsavedChanges = () => { + if (!this._attributes) { + throw new Error('Invalid usage, must await loadAttributes before calling hasUnsavedChanges'); + } + + const savedLayerList = this._attributes.layerListJSON + ? JSON.parse(this._attributes.layerListJSON) + : null; + const layerListConfigOnly = getLayerListConfigOnly(this._store.getState()); + return !savedLayerList + ? !_.isEqual(layerListConfigOnly, this._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(layerListConfigOnly)), savedLayerList); + }; + + setBreadcrumbs() { + if (!this._attributes) { + throw new Error('Invalid usage, must await loadAttributes before calling hasUnsavedChanges'); + } + + const breadcrumbs = getBreadcrumbs({ + title: this._attributes.title, + getHasUnsavedChanges: this.hasUnsavedChanges, + originatingApp: this._originatingApp, + getAppNameFromId: this._stateTransfer.getAppNameFromId, + }); + getCoreChrome().setBreadcrumbs(breadcrumbs); + } + public getSavedObjectId(): string | undefined { return this._mapEmbeddableInput?.savedObjectId; } + public getOriginatingApp(): string | undefined { + return this._originatingApp; + } + + public getAppNameFromId = (appId: string): string | undefined => { + return this._stateTransfer.getAppNameFromId(appId); + }; + + public hasSaveAndReturnConfig() { + return !!this._originatingApp; + } + public getAttributes(): MapSavedObjectAttributes { if (!this._attributes) { throw new Error('Invalid usage, must await loadAttributes before calling getAttributes'); @@ -87,15 +188,9 @@ export class SavedMap { onTitleDuplicate, returnToOrigin, saveByReference, - originatingApp, - stateTransfer, - setBreadcrumbs, }: OnSaveProps & { returnToOrigin: boolean; saveByReference: boolean; - originatingApp?: string; - stateTransfer: EmbeddableStateTransfer; - setBreadcrumbs: (title: string) => void; }) { if (!this._attributes) { throw new Error('Invalid usage, must await loadAttributes before calling save'); @@ -146,7 +241,7 @@ export class SavedMap { } if (returnToOrigin) { - if (!originatingApp) { + if (!this._originatingApp) { getToasts().addDanger({ title: i18n.translate('xpack.maps.topNav.saveErrorMessage', { defaultMessage: `Error saving '{title}'`, @@ -158,7 +253,7 @@ export class SavedMap { }); return; } - stateTransfer.navigateToWithEmbeddablePackage(originatingApp, { + this._stateTransfer.navigateToWithEmbeddablePackage(this._originatingApp, { state: { embeddableId: newCopyOnSave ? undefined : this._embeddableId, type: MAP_SAVED_OBJECT_TYPE, @@ -168,6 +263,8 @@ export class SavedMap { return; } + // break connection to originating application + this._originatingApp = undefined; getToasts().addSuccess({ title: i18n.translate('xpack.maps.topNav.saveSuccessMessage', { defaultMessage: `Saved '{title}'`, @@ -176,9 +273,9 @@ export class SavedMap { }); getCoreChrome().docTitle.change(newTitle); - setBreadcrumbs(newTitle); + this.setBreadcrumbs(); goToSpecifiedPath(`/map/${updatedMapEmbeddableInput.savedObjectId}${window.location.hash}`); - return { id: updatedMapEmbeddableInput.savedObjectId }; + return; } private _syncAttributesWithStore() { diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx index 7d8989cfdc76f..2869eb75ff838 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx @@ -29,7 +29,7 @@ import { EmbeddableStateTransfer } from '../../../../../../../src/plugins/embedd function getSaveAndReturnButtonLabel() { return getIsAllowByValueEmbeddables() ? i18n.translate('xpack.maps.topNav.saveToMaps', { - defaultMessage: 'Save to Maps', + defaultMessage: 'Save to maps', }) : i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { defaultMessage: 'Save as', @@ -43,9 +43,7 @@ export function getTopNavConfig({ enableFullScreen, openMapSettings, inspectorAdapters, - setBreadcrumbs, - stateTransfer, - originatingApp, + getAppNameFromId, }: { savedMap: SavedMap; isOpenSettingsDisabled: boolean; @@ -53,8 +51,6 @@ export function getTopNavConfig({ enableFullScreen: () => void; openMapSettings: () => void; inspectorAdapters: Adapters; - setBreadcrumbs: (title: string) => void; - stateTransfer?: EmbeddableStateTransfer; }) { const topNavConfigs = []; @@ -105,7 +101,7 @@ export function getTopNavConfig({ ); if (getMapsCapabilities().save) { - const hasSaveAndReturnConfig = originatingApp; + const hasSaveAndReturnConfig = savedMap.hasSaveAndReturnConfig(); const mapSavedObjectAttributes = savedMap.getAttributes(); topNavConfigs.push({ @@ -134,16 +130,15 @@ export function getTopNavConfig({ run: () => { const saveModal = ( { - return savedMap.save({ + originatingApp={savedMap.getOriginatingApp()} + getAppNameFromId={savedMap.getAppNameFromId} + onSave={async (props: OnSaveProps & { returnToOrigin: boolean }) => { + await savedMap.save({ ...props, saveByReference: true, - originatingApp, - stateTransfer, - setBreadcrumbs, }); + // showSaveModal wrapper requires onSave to return an object with an id to close the modal after save + return { id: 'id' }; }} onClose={() => {}} documentInfo={{ @@ -169,7 +164,7 @@ export function getTopNavConfig({ emphasize: true, iconType: 'checkInCircleFilled', run: () => { - return savedMap.save({ + savedMap.save({ newTitle: mapSavedObjectAttributes.title ? mapSavedObjectAttributes.title : '', newDescription: mapSavedObjectAttributes.description ? mapSavedObjectAttributes.description @@ -179,9 +174,6 @@ export function getTopNavConfig({ returnToOrigin: true, onTitleDuplicate: () => {}, saveByReference: false, - originatingApp, - stateTransfer, - setBreadcrumbs, }); }, testId: 'mapSaveAndReturnButton', From a9c3c10d12d297a547a67ea7f054b24c4031e809 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 05:29:23 -0700 Subject: [PATCH 15/35] clean up file structure --- .../maps/public/embeddable/map_embeddable.tsx | 5 +-- .../public/lazy_load_bundle/lazy/index.ts | 2 +- .../maps/public/{routing => }/render_app.tsx | 11 +++--- x-pack/plugins/maps/public/routes/index.ts | 8 +++++ .../plugins/maps/public/routes/list/index.ts | 7 ++++ .../routes/list/load_list_and_render.tsx | 5 ++- .../routes/list/maps_list_view.tsx | 10 +++--- .../{routing => }/routes/map_app/index.ts | 3 +- .../{routing => }/routes/map_app/map_app.tsx | 35 ++++++++++--------- .../routes/map_app/map_app_connector.ts | 18 +++++----- .../routes/map_app/map_app_container.tsx | 0 .../saved_map}/get_breadcrumbs.test.tsx | 2 +- .../map_app/saved_map}/get_breadcrumbs.tsx | 2 +- .../saved_map}/get_initial_layers.test.js | 18 +++++----- .../map_app/saved_map}/get_initial_layers.ts | 24 +++++-------- .../map_app/saved_map}/get_initial_query.ts | 4 +-- .../saved_map}/get_initial_refresh_config.ts | 4 +-- .../saved_map}/get_initial_time_filters.ts | 2 +- .../public/routes/map_app/saved_map/index.ts | 11 ++++++ .../saved_map}/map_attribute_service.ts | 21 +++++++---- .../map_app/saved_map}/saved_map.ts | 6 ++-- .../routes/map_app/top_nav_config.tsx | 8 ++--- .../map_app/url_state}/app_state_manager.ts | 0 .../map_app/url_state}/app_sync.ts | 11 +++--- .../map_app/url_state}/global_sync.ts | 6 ++-- .../public/routes/map_app/url_state/index.ts | 14 ++++++++ 26 files changed, 140 insertions(+), 97 deletions(-) rename x-pack/plugins/maps/public/{routing => }/render_app.tsx (91%) create mode 100644 x-pack/plugins/maps/public/routes/index.ts create mode 100644 x-pack/plugins/maps/public/routes/list/index.ts rename x-pack/plugins/maps/public/{routing => }/routes/list/load_list_and_render.tsx (86%) rename x-pack/plugins/maps/public/{routing => }/routes/list/maps_list_view.tsx (98%) rename x-pack/plugins/maps/public/{routing => }/routes/map_app/index.ts (73%) rename x-pack/plugins/maps/public/{routing => }/routes/map_app/map_app.tsx (91%) rename x-pack/plugins/maps/public/{routing => }/routes/map_app/map_app_connector.ts (79%) rename x-pack/plugins/maps/public/{routing => }/routes/map_app/map_app_container.tsx (100%) rename x-pack/plugins/maps/public/{routing/routes/map_app => routes/map_app/saved_map}/get_breadcrumbs.test.tsx (96%) rename x-pack/plugins/maps/public/{routing/routes/map_app => routes/map_app/saved_map}/get_breadcrumbs.tsx (96%) rename x-pack/plugins/maps/public/{routing/bootstrap => routes/map_app/saved_map}/get_initial_layers.test.js (81%) rename x-pack/plugins/maps/public/{routing/bootstrap => routes/map_app/saved_map}/get_initial_layers.ts (68%) rename x-pack/plugins/maps/public/{routing/bootstrap => routes/map_app/saved_map}/get_initial_query.ts (84%) rename x-pack/plugins/maps/public/{routing/bootstrap => routes/map_app/saved_map}/get_initial_refresh_config.ts (87%) rename x-pack/plugins/maps/public/{routing/bootstrap => routes/map_app/saved_map}/get_initial_time_filters.ts (92%) create mode 100644 x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts rename x-pack/plugins/maps/public/{ => routes/map_app/saved_map}/map_attribute_service.ts (78%) rename x-pack/plugins/maps/public/{routing/routes/map_app => routes/map_app/saved_map}/saved_map.ts (98%) rename x-pack/plugins/maps/public/{routing => }/routes/map_app/top_nav_config.tsx (95%) rename x-pack/plugins/maps/public/{routing/state_syncing => routes/map_app/url_state}/app_state_manager.ts (100%) rename x-pack/plugins/maps/public/{routing/state_syncing => routes/map_app/url_state}/app_sync.ts (90%) rename x-pack/plugins/maps/public/{routing/state_syncing => routes/map_app/url_state}/global_sync.ts (83%) create mode 100644 x-pack/plugins/maps/public/routes/map_app/url_state/index.ts diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 21d8b99107be7..ffb7b31ff82ee 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -72,8 +72,9 @@ import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapContainer } from '../connected_components/map_container'; -import { getMapAttributeService } from '../map_attribute_service'; -import { getInitialLayers } from '../routing/bootstrap/get_initial_layers'; +// TODO use SavedMap instead of getMapAttributeService and getInitialLayers +import { getMapAttributeService } from '../routes/map_app/saved_map/map_attribute_service'; +import { getInitialLayers } from '../routes/map_app/saved_map/get_initial_layers'; import { getIndexPatternsFromIds } from '../index_pattern_util'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts index b7ed090492a88..c0d9b61bfc014 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts @@ -9,7 +9,7 @@ export * from '../../embeddable/map_embeddable'; export * from '../../kibana_services'; -export { renderApp } from '../../routing/render_app'; +export { renderApp } from '../../render_app'; export * from '../../classes/layers/solution_layers/security'; export { registerLayerWizard } from '../../classes/layers/layer_wizard_registry'; export { registerSource } from '../../classes/sources/source_registry'; diff --git a/x-pack/plugins/maps/public/routing/render_app.tsx b/x-pack/plugins/maps/public/render_app.tsx similarity index 91% rename from x-pack/plugins/maps/public/routing/render_app.tsx rename to x-pack/plugins/maps/public/render_app.tsx index f20552be8dc34..d33f4d455131f 100644 --- a/x-pack/plugins/maps/public/routing/render_app.tsx +++ b/x-pack/plugins/maps/public/render_app.tsx @@ -16,14 +16,13 @@ import { getMapsCapabilities, getToasts, getEmbeddableService, -} from '../kibana_services'; +} from './kibana_services'; import { createKbnUrlStateStorage, withNotifyOnErrors, IKbnUrlStateStorage, -} from '../../../../../src/plugins/kibana_utils/public'; -import { LoadListAndRender } from './routes/list/load_list_and_render'; -import { MapAppContainer, MapApp, SavedMap } from './routes/map_app'; +} from '../../../../src/plugins/kibana_utils/public'; +import { MapList, MapApp } from './routes'; export let goToSpecifiedPath: (path: string) => void; export let kbnUrlStateStorage: IKbnUrlStateStorage; @@ -72,7 +71,7 @@ export async function renderApp({ } return ( - ; } else if (pathname === '/' || pathname === '') { - return ; + return ; } else { return ; } diff --git a/x-pack/plugins/maps/public/routes/index.ts b/x-pack/plugins/maps/public/routes/index.ts new file mode 100644 index 0000000000000..d790c8f226f1e --- /dev/null +++ b/x-pack/plugins/maps/public/routes/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { MapApp, SavedMap } from './map_app'; +export { MapList } from './list'; diff --git a/x-pack/plugins/maps/public/routes/list/index.ts b/x-pack/plugins/maps/public/routes/list/index.ts new file mode 100644 index 0000000000000..abebdfd2cf8cd --- /dev/null +++ b/x-pack/plugins/maps/public/routes/list/index.ts @@ -0,0 +1,7 @@ +/* + * 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. + */ + +export { LoadListAndRender as MapList } from './load_list_and_render'; diff --git a/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx b/x-pack/plugins/maps/public/routes/list/load_list_and_render.tsx similarity index 86% rename from x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx rename to x-pack/plugins/maps/public/routes/list/load_list_and_render.tsx index 1db60604af539..087fd82300ce3 100644 --- a/x-pack/plugins/maps/public/routing/routes/list/load_list_and_render.tsx +++ b/x-pack/plugins/maps/public/routes/list/load_list_and_render.tsx @@ -7,10 +7,9 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { Redirect } from 'react-router-dom'; -import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; -import { getSavedObjectsClient, getToasts } from '../../../kibana_services'; +import { getSavedObjectsClient, getToasts } from '../../kibana_services'; import { MapsListView } from './maps_list_view'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; export class LoadListAndRender extends React.Component { _isMounted: boolean = false; diff --git a/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx similarity index 98% rename from x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx rename to x-pack/plugins/maps/public/routes/list/maps_list_view.tsx index 6cf7bed62fa7d..cfe3f3165ce4f 100644 --- a/x-pack/plugins/maps/public/routing/routes/list/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx @@ -32,8 +32,8 @@ import { import { EuiTableSortingType } from '@elastic/eui'; import { goToSpecifiedPath } from '../../render_app'; // @ts-expect-error -import { addHelpMenuToAppChrome } from '../../../help_menu_util'; -import { APP_ID, MAP_PATH, MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +import { addHelpMenuToAppChrome } from '../../help_menu_util'; +import { APP_ID, MAP_PATH, MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; import { getMapsCapabilities, getUiSettings, @@ -41,9 +41,9 @@ import { getCoreChrome, getNavigateToApp, getSavedObjectsClient, -} from '../../../kibana_services'; -import { getAppTitle } from '../../../../common/i18n_getters'; -import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +} from '../../kibana_services'; +import { getAppTitle } from '../../../common/i18n_getters'; +import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; export const EMPTY_FILTER = ''; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/index.ts b/x-pack/plugins/maps/public/routes/map_app/index.ts similarity index 73% rename from x-pack/plugins/maps/public/routing/routes/map_app/index.ts rename to x-pack/plugins/maps/public/routes/map_app/index.ts index 0a56686e26314..6afeb9f06fd01 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/index.ts +++ b/x-pack/plugins/maps/public/routes/map_app/index.ts @@ -4,6 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { MapApp } from './map_app_connector'; export { SavedMap } from './saved_map'; -export { MapAppContainer } from './map_app_container'; +export { MapAppContainer as MapApp } from './map_app_container'; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx similarity index 91% rename from x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx rename to x-pack/plugins/maps/public/routes/map_app/map_app.tsx index 3020db1a50cef..f469e01da1380 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx @@ -17,18 +17,15 @@ import { getMapsCapabilities, getNavigation, getToasts, -} from '../../../kibana_services'; -import { getInitialTimeFilters } from '../../bootstrap/get_initial_time_filters'; -import { getInitialRefreshConfig } from '../../bootstrap/get_initial_refresh_config'; -import { getInitialQuery } from '../../bootstrap/get_initial_query'; +} from '../../kibana_services'; import { + AppStateManager, + startAppStateSyncing, getGlobalState, updateGlobalState, startGlobalStateSyncing, MapsGlobalState, -} from '../../state_syncing/global_sync'; -import { AppStateManager } from '../../state_syncing/app_state_manager'; -import { startAppStateSyncing } from '../../state_syncing/app_sync'; +} from './url_state'; import { esFilters, Filter, @@ -38,22 +35,28 @@ import { SavedQuery, QueryStateChange, QueryState, -} from '../../../../../../../src/plugins/data/public'; -import { MapContainer } from '../../../connected_components/map_container'; -import { getIndexPatternsFromIds } from '../../../index_pattern_util'; +} from '../../../../../../src/plugins/data/public'; +import { MapContainer } from '../../connected_components/map_container'; +import { getIndexPatternsFromIds } from '../../index_pattern_util'; import { getTopNavConfig } from './top_nav_config'; -import { getBreadcrumbs, unsavedChangesTitle, unsavedChangesWarning } from './get_breadcrumbs'; import { LayerDescriptor, MapRefreshConfig, MapCenterAndZoom, MapQuery, -} from '../../../../common/descriptor_types'; -import { MapSettings } from '../../../reducers/map'; +} from '../../../common/descriptor_types'; +import { MapSettings } from '../../reducers/map'; import { goToSpecifiedPath } from '../../render_app'; -import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; -import { getExistingMapPath } from '../../../../common/constants'; -import { SavedMap } from './saved_map'; +import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; +import { getExistingMapPath } from '../../../common/constants'; +import { + getInitialQuery, + getInitialRefreshConfig, + getInitialTimeFilters, + SavedMap, + unsavedChangesTitle, + unsavedChangesWarning, +} from './saved_map'; interface Props { savedMap: SavedMap; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts similarity index 79% rename from x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts rename to x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts index 1d8423578b54a..ba7535fda7bf8 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_connector.ts +++ b/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts @@ -9,7 +9,7 @@ import { ThunkDispatch } from 'redux-thunk'; import { AnyAction } from 'redux'; import { Filter, Query, TimeRange } from 'src/plugins/data/public'; import { MapApp } from './map_app'; -import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors'; +import { getFlyoutDisplay, getIsFullScreen } from '../../selectors/ui_selectors'; import { getFilters, getQuery, @@ -17,18 +17,18 @@ import { getRefreshConfig, getTimeFilters, hasDirtyState, -} from '../../../selectors/map_selectors'; -import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../../actions'; -import { FLYOUT_STATE } from '../../../reducers/ui'; -import { getMapsCapabilities } from '../../../kibana_services'; -import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; -import { MapStoreState } from '../../../reducers/store'; +} from '../../selectors/map_selectors'; +import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../actions'; +import { FLYOUT_STATE } from '../../reducers/ui'; +import { getMapsCapabilities } from '../../kibana_services'; +import { getInspectorAdapters } from '../../reducers/non_serializable_instances'; +import { MapStoreState } from '../../reducers/store'; import { MapRefreshConfig, MapCenterAndZoom, LayerDescriptor, -} from '../../../../common/descriptor_types'; -import { MapSettings } from '../../../reducers/map'; +} from '../../../common/descriptor_types'; +import { MapSettings } from '../../reducers/map'; function mapStateToProps(state: MapStoreState) { return { diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx similarity index 100% rename from x-pack/plugins/maps/public/routing/routes/map_app/map_app_container.tsx rename to x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.test.tsx b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx similarity index 96% rename from x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.test.tsx rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx index 3516daf526968..202e9350b4fe0 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.test.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx @@ -7,7 +7,7 @@ import { getBreadcrumbs } from './get_breadcrumbs'; jest.mock('../../../kibana_services', () => {}); -jest.mock('../../render_app', () => {}); +jest.mock('../../../render_app', () => {}); const getHasUnsavedChanges = () => { return false; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.tsx b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx similarity index 96% rename from x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.tsx rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx index 88dba0f83ec2f..4def1f33334b2 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/get_breadcrumbs.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { getCoreOverlays, getNavigateToApp } from '../../../kibana_services'; -import { goToSpecifiedPath } from '../../render_app'; +import { goToSpecifiedPath } from '../../../render_app'; import { getAppTitle } from '../../../../common/i18n_getters'; export const unsavedChangesWarning = i18n.translate( diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.test.js b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.test.js similarity index 81% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.test.js rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.test.js index 4de29e6f028e1..d2068d220d4bd 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.test.js +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.test.js @@ -4,10 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../meta', () => { +jest.mock('../../../meta', () => { return {}; }); -jest.mock('../../kibana_services'); +jest.mock('../../../kibana_services'); import { getInitialLayers } from './get_initial_layers'; @@ -15,7 +15,7 @@ const layerListNotProvided = undefined; describe('Saved object has layer list', () => { beforeEach(() => { - require('../../kibana_services').getIsEmsEnabled = () => true; + require('../../../kibana_services').getIsEmsEnabled = () => true; }); it('Should get initial layers from saved object', () => { @@ -32,7 +32,7 @@ describe('Saved object has layer list', () => { describe('kibana.yml configured with map.tilemap.url', () => { beforeAll(() => { - require('../../meta').getKibanaTileMap = () => { + require('../../../meta').getKibanaTileMap = () => { return { url: 'myTileUrl', }; @@ -62,11 +62,11 @@ describe('kibana.yml configured with map.tilemap.url', () => { describe('EMS is enabled', () => { beforeAll(() => { - require('../../meta').getKibanaTileMap = () => { + require('../../../meta').getKibanaTileMap = () => { return null; }; - require('../../kibana_services').getIsEmsEnabled = () => true; - require('../../kibana_services').getEmsTileLayerId = () => ({ + require('../../../kibana_services').getIsEmsEnabled = () => true; + require('../../../kibana_services').getEmsTileLayerId = () => ({ bright: 'road_map', desaturated: 'road_map_desaturated', dark: 'dark_map', @@ -98,10 +98,10 @@ describe('EMS is enabled', () => { describe('EMS is not enabled', () => { beforeAll(() => { - require('../../meta').getKibanaTileMap = () => { + require('../../../meta').getKibanaTileMap = () => { return null; }; - require('../../kibana_services').getIsEmsEnabled = () => false; + require('../../../kibana_services').getIsEmsEnabled = () => false; }); it('Should return empty layer list since there are no configured tile layers', () => { diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts similarity index 68% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts index e828dc88409cb..f7d42dbbeab96 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts @@ -7,25 +7,17 @@ import _ from 'lodash'; import rison from 'rison-node'; import { i18n } from '@kbn/i18n'; -// Import each layer type, even those not used, to init in registry -import '../../classes/sources/wms_source'; -import '../../classes/sources/ems_file_source'; -import '../../classes/sources/es_search_source'; -import '../../classes/sources/es_pew_pew_source'; -import '../../classes/sources/kibana_regionmap_source'; -import '../../classes/sources/es_geo_grid_source'; -import '../../classes/sources/xyz_tms_source'; -import { LayerDescriptor } from '../../../common/descriptor_types'; +import { LayerDescriptor } from '../../../../common/descriptor_types'; // @ts-expect-error -import { KibanaTilemapSource } from '../../classes/sources/kibana_tilemap_source'; -import { TileLayer } from '../../classes/layers/tile_layer/tile_layer'; +import { KibanaTilemapSource } from '../../../classes/sources/kibana_tilemap_source'; +import { TileLayer } from '../../../classes/layers/tile_layer/tile_layer'; // @ts-expect-error -import { EMSTMSSource } from '../../classes/sources/ems_tms_source'; +import { EMSTMSSource } from '../../../classes/sources/ems_tms_source'; // @ts-expect-error -import { VectorTileLayer } from '../../classes/layers/vector_tile_layer/vector_tile_layer'; -import { getIsEmsEnabled, getToasts } from '../../kibana_services'; -import { INITIAL_LAYERS_KEY } from '../../../common/constants'; -import { getKibanaTileMap } from '../../meta'; +import { VectorTileLayer } from '../../../classes/layers/vector_tile_layer/vector_tile_layer'; +import { getIsEmsEnabled, getToasts } from '../../../kibana_services'; +import { INITIAL_LAYERS_KEY } from '../../../../common/constants'; +import { getKibanaTileMap } from '../../../meta'; export function getInitialLayers(layerListJSON?: string, initialLayers: LayerDescriptor[] = []) { if (layerListJSON) { diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_query.ts similarity index 84% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_query.ts index 43293d152dbff..85fe1950d9c2d 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_query.ts @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getData } from '../../kibana_services'; -import { MapsAppState } from '../state_syncing/app_state_manager'; +import { getData } from '../../../kibana_services'; +import { MapsAppState } from '../url_state'; export function getInitialQuery({ mapStateJSON, diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_refresh_config.ts similarity index 87% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_refresh_config.ts index 7d759cb25052f..a9c52beb7d906 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_refresh_config.ts @@ -5,8 +5,8 @@ */ import { QueryState } from 'src/plugins/data/public'; -import { getUiSettings } from '../../kibana_services'; -import { UI_SETTINGS } from '../../../../../../src/plugins/data/public'; +import { getUiSettings } from '../../../kibana_services'; +import { UI_SETTINGS } from '../../../../../../../src/plugins/data/public'; export function getInitialRefreshConfig({ mapStateJSON, diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_time_filters.ts similarity index 92% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_time_filters.ts index 549cc154fe487..93197bb88dc28 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_time_filters.ts @@ -5,7 +5,7 @@ */ import { QueryState } from 'src/plugins/data/public'; -import { getUiSettings } from '../../kibana_services'; +import { getUiSettings } from '../../../kibana_services'; export function getInitialTimeFilters({ mapStateJSON, diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts new file mode 100644 index 0000000000000..287522bb22145 --- /dev/null +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export { SavedMap } from './saved_map'; +export { getInitialQuery } from './get_initial_query'; +export { getInitialRefreshConfig } from './get_initial_refresh_config'; +export { getInitialTimeFilters } from './get_initial_time_filters'; +export { unsavedChangesTitle, unsavedChangesWarning } from './get_breadcrumbs'; diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts similarity index 78% rename from x-pack/plugins/maps/public/map_attribute_service.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts index 63dcdc8ad46fa..96194f1030e3b 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts @@ -4,14 +4,21 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AttributeService } from '../../../../src/plugins/embeddable/public'; -import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; -import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; -import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; -import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; -import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; +import { AttributeService } from '../../../../../../../src/plugins/embeddable/public'; +import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +import { MapByValueInput, MapByReferenceInput } from '../../../embeddable/types'; +import { + checkForDuplicateTitle, + OnSaveProps, +} from '../../../../../../../src/plugins/saved_objects/public'; +import { + getCoreOverlays, + getEmbeddableService, + getSavedObjectsClient, +} from '../../../kibana_services'; // @ts-expect-error -import { extractReferences, injectReferences } from '../common/migrations/references'; +import { extractReferences, injectReferences } from '../../../../common/migrations/references'; export type MapAttributeService = AttributeService< MapSavedObjectAttributes, diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts similarity index 98% rename from x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts rename to x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index 7a60b9d4265ea..9772598c05f53 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -29,7 +29,7 @@ import { setOpenTOCDetails, } from '../../../actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; -import { getMapAttributeService } from '../../../map_attribute_service'; +import { getMapAttributeService } from './map_attribute_service'; import { checkForDuplicateTitle, OnSaveProps, @@ -41,9 +41,9 @@ import { getSavedObjectsClient, getToasts, } from '../../../kibana_services'; -import { goToSpecifiedPath } from '../../render_app'; +import { goToSpecifiedPath } from '../../../render_app'; import { LayerDescriptor } from '../../../../common/descriptor_types'; -import { getInitialLayers, getInitialLayersFromUrlParam } from '../../bootstrap/get_initial_layers'; +import { getInitialLayers, getInitialLayersFromUrlParam } from './get_initial_layers'; import { copyPersistentState } from '../../../reducers/util'; import { getBreadcrumbs } from './get_breadcrumbs'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; diff --git a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx similarity index 95% rename from x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx rename to x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx index 2869eb75ff838..c4ce2bbee553c 100644 --- a/x-pack/plugins/maps/public/routing/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx @@ -15,16 +15,16 @@ import { getCoreI18n, getNavigateToApp, getIsAllowByValueEmbeddables, -} from '../../../kibana_services'; +} from '../../kibana_services'; import { SavedObjectSaveModalOrigin, OnSaveProps, showSaveModal, -} from '../../../../../../../src/plugins/saved_objects/public'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +} from '../../../../../../src/plugins/saved_objects/public'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; import { goToSpecifiedPath } from '../../render_app'; import { SavedMap } from './saved_map'; -import { EmbeddableStateTransfer } from '../../../../../../../src/plugins/embeddable/public'; +import { EmbeddableStateTransfer } from '../../../../../../src/plugins/embeddable/public'; function getSaveAndReturnButtonLabel() { return getIsAllowByValueEmbeddables() diff --git a/x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.ts b/x-pack/plugins/maps/public/routes/map_app/url_state/app_state_manager.ts similarity index 100% rename from x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.ts rename to x-pack/plugins/maps/public/routes/map_app/url_state/app_state_manager.ts diff --git a/x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts b/x-pack/plugins/maps/public/routes/map_app/url_state/app_sync.ts similarity index 90% rename from x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts rename to x-pack/plugins/maps/public/routes/map_app/url_state/app_sync.ts index 498442040681c..5c6274d5a619d 100644 --- a/x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts +++ b/x-pack/plugins/maps/public/routes/map_app/url_state/app_sync.ts @@ -5,10 +5,13 @@ */ import { map } from 'rxjs/operators'; -import { connectToQueryState, esFilters } from '../../../../../../src/plugins/data/public'; -import { syncState, BaseStateContainer } from '../../../../../../src/plugins/kibana_utils/public'; -import { getData } from '../../kibana_services'; -import { kbnUrlStateStorage } from '../render_app'; +import { connectToQueryState, esFilters } from '../../../../../../../src/plugins/data/public'; +import { + syncState, + BaseStateContainer, +} from '../../../../../../../src/plugins/kibana_utils/public'; +import { getData } from '../../../kibana_services'; +import { kbnUrlStateStorage } from '../../../render_app'; import { AppStateManager } from './app_state_manager'; export function startAppStateSyncing(appStateManager: AppStateManager) { diff --git a/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts b/x-pack/plugins/maps/public/routes/map_app/url_state/global_sync.ts similarity index 83% rename from x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts rename to x-pack/plugins/maps/public/routes/map_app/url_state/global_sync.ts index 3f370d9aa99b2..7fefc6662ada7 100644 --- a/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts +++ b/x-pack/plugins/maps/public/routes/map_app/url_state/global_sync.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ import { TimeRange, RefreshInterval, Filter } from 'src/plugins/data/public'; -import { syncQueryStateWithUrl } from '../../../../../../src/plugins/data/public'; -import { getData } from '../../kibana_services'; -import { kbnUrlStateStorage } from '../render_app'; +import { syncQueryStateWithUrl } from '../../../../../../../src/plugins/data/public'; +import { getData } from '../../../kibana_services'; +import { kbnUrlStateStorage } from '../../../render_app'; export interface MapsGlobalState { time?: TimeRange; diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts b/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts new file mode 100644 index 0000000000000..fda19bed25be7 --- /dev/null +++ b/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export { + getGlobalState, + updateGlobalState, + startGlobalStateSyncing, + MapsGlobalState, +} from './global_sync'; +export { AppStateManager } from './app_state_manager'; +export { startAppStateSyncing } from './app_sync'; From 87126ad8dc4fb7fe67a5541bb7dd38b27b7f38bd Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 05:38:30 -0700 Subject: [PATCH 16/35] clean up adding help menu --- x-pack/plugins/maps/public/help_menu_util.js | 26 ---------- x-pack/plugins/maps/public/render_app.tsx | 47 ++++++++++++++----- .../public/routes/list/maps_list_view.tsx | 3 -- 3 files changed, 34 insertions(+), 42 deletions(-) delete mode 100644 x-pack/plugins/maps/public/help_menu_util.js diff --git a/x-pack/plugins/maps/public/help_menu_util.js b/x-pack/plugins/maps/public/help_menu_util.js deleted file mode 100644 index 053caf6688309..0000000000000 --- a/x-pack/plugins/maps/public/help_menu_util.js +++ /dev/null @@ -1,26 +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 { getDocLinks, getCoreChrome } from './kibana_services'; - -export function addHelpMenuToAppChrome() { - const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = getDocLinks(); - - getCoreChrome().setHelpExtension({ - appName: 'Maps', - links: [ - { - linkType: 'documentation', - href: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/maps.html`, - }, - { - linkType: 'github', - title: '[Maps]', - labels: ['Team:Geo'], - }, - ], - }); -} diff --git a/x-pack/plugins/maps/public/render_app.tsx b/x-pack/plugins/maps/public/render_app.tsx index d33f4d455131f..29b1464af4ca5 100644 --- a/x-pack/plugins/maps/public/render_app.tsx +++ b/x-pack/plugins/maps/public/render_app.tsx @@ -16,6 +16,7 @@ import { getMapsCapabilities, getToasts, getEmbeddableService, + getDocLinks, } from './kibana_services'; import { createKbnUrlStateStorage, @@ -27,6 +28,37 @@ import { MapList, MapApp } from './routes'; export let goToSpecifiedPath: (path: string) => void; export let kbnUrlStateStorage: IKbnUrlStateStorage; +function setAppChrome() { + if (!getMapsCapabilities().save) { + getCoreChrome().setBadge({ + text: i18n.translate('xpack.maps.badge.readOnly.text', { + defaultMessage: 'Read only', + }), + tooltip: i18n.translate('xpack.maps.badge.readOnly.tooltip', { + defaultMessage: 'Unable to save maps', + }), + iconType: 'glasses', + }); + } + + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = getDocLinks(); + + getCoreChrome().setHelpExtension({ + appName: 'Maps', + links: [ + { + linkType: 'documentation', + href: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/maps.html`, + }, + { + linkType: 'github', + title: '[Maps]', + labels: ['Team:Geo'], + }, + ], + }); +} + export async function renderApp({ element, history, @@ -40,19 +72,7 @@ export async function renderApp({ ...withNotifyOnErrors(getToasts()), }); - const I18nContext = getCoreI18n().Context; - - if (!getMapsCapabilities().save) { - getCoreChrome().setBadge({ - text: i18n.translate('xpack.maps.badge.readOnly.text', { - defaultMessage: 'Read only', - }), - tooltip: i18n.translate('xpack.maps.badge.readOnly.tooltip', { - defaultMessage: 'Unable to save maps', - }), - iconType: 'glasses', - }); - } + setAppChrome(); function renderMapApp(routeProps: RouteComponentProps<{ savedMapId?: string }>) { const stateTransfer = getEmbeddableService()?.getStateTransfer( @@ -82,6 +102,7 @@ export async function renderApp({ ); } + const I18nContext = getCoreI18n().Context; render( diff --git a/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx index cfe3f3165ce4f..4e9902065f8b4 100644 --- a/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx @@ -31,8 +31,6 @@ import { } from '@elastic/eui/src/components/basic_table/basic_table'; import { EuiTableSortingType } from '@elastic/eui'; import { goToSpecifiedPath } from '../../render_app'; -// @ts-expect-error -import { addHelpMenuToAppChrome } from '../../help_menu_util'; import { APP_ID, MAP_PATH, MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; import { getMapsCapabilities, @@ -104,7 +102,6 @@ export class MapsListView extends React.Component { async initMapList() { this.fetchItems(); - addHelpMenuToAppChrome(); getCoreChrome().docTitle.change(getAppTitle()); getCoreChrome().setBreadcrumbs([{ text: getAppTitle() }]); } From 2370a1b7735914f912fa34eed4d92dab3b1dd57b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 07:45:44 -0700 Subject: [PATCH 17/35] use SavedMap in map_embeddable to remove dupicated load attributes code --- .../maps/public/embeddable/map_embeddable.tsx | 166 ++++++------------ .../saved_map => }/map_attribute_service.ts | 21 +-- .../maps/public/routes/map_app/map_app.tsx | 6 +- .../public/routes/map_app/saved_map/index.ts | 1 + .../routes/map_app/saved_map/saved_map.ts | 90 +++++++--- .../maps/public/selectors/map_selectors.ts | 26 ++- 6 files changed, 150 insertions(+), 160 deletions(-) rename x-pack/plugins/maps/public/{routes/map_app/saved_map => }/map_attribute_service.ts (78%) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index ffb7b31ff82ee..bbe1b28443be3 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -29,11 +29,9 @@ import { Query, RefreshInterval, } from '../../../../../src/plugins/data/public'; -import { createMapStore, MapStore } from '../reducers/store'; import { MapSettings } from '../reducers/map'; import { addLayerWithoutDataSync, - setGotoWithCenter, replaceLayerList, setQuery, setRefreshConfig, @@ -43,11 +41,7 @@ import { hideToolbarOverlay, hideLayerControl, hideViewControl, - setHiddenLayers, - setMapSettings, setReadOnly, - setIsLayerTOCOpen, - setOpenTOCDetails, } from '../actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors'; import { @@ -60,6 +54,7 @@ import { getMapZoom, getHiddenLayerIds, getQueryableUniqueIndexPatternIds, + getLayerListRaw, } from '../selectors/map_selectors'; import { APP_ID, @@ -72,11 +67,10 @@ import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapContainer } from '../connected_components/map_container'; -// TODO use SavedMap instead of getMapAttributeService and getInitialLayers -import { getMapAttributeService } from '../routes/map_app/saved_map/map_attribute_service'; -import { getInitialLayers } from '../routes/map_app/saved_map/get_initial_layers'; +import { SavedMap } from '../routes/map_app/saved_map'; import { getIndexPatternsFromIds } from '../index_pattern_util'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; +import { getMapAttributeService } from '../map_attribute_service'; import { MapByValueInput, @@ -87,16 +81,13 @@ import { } from './types'; export { MapEmbeddableInput }; -const attributeService = getMapAttributeService(); - export class MapEmbeddable extends Embeddable implements ReferenceOrValueEmbeddable { type = MAP_SAVED_OBJECT_TYPE; - private _attributes: MapSavedObjectAttributes | null = null; + private _savedMap: SavedMap; private _renderTooltipContent?: RenderToolTipContent; - private _store: MapStore; private _subscription: Subscription; private _prevTimeRange?: TimeRange; private _prevQuery?: Query; @@ -116,13 +107,19 @@ export class MapEmbeddable parent ); - this._store = createMapStore(); - this.initialize(initialInput); + this._savedMap = new SavedMap({ mapEmbeddableInput: initialInput }); + this.initializeSaveMap(); this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input)); } - private async initialize(input: MapEmbeddableInput) { - this._attributes = await attributeService.unwrapAttributes(input); + private async initializeSaveMap() { + const overrides = { + isLayerTOCOpen: this.input.isLayerTOCOpen, + openTOCDetails: this.input.openTOCDetails, + mapCenter: this.input.mapCenter, + hiddenLayers: this.input.hiddenLayers, + }; + await this._savedMap.loadAttributes(overrides); this.initializeStore(); this.initializeOutput(); this._isInitialized = true; @@ -132,85 +129,33 @@ export class MapEmbeddable } private async initializeStore() { - this._store.dispatch(setReadOnly(true)); - this._store.dispatch(disableScrollZoom()); - - if (this._attributes?.mapStateJSON) { - const mapState = JSON.parse(this._attributes.mapStateJSON); - if (mapState.settings) { - this._store.dispatch(setMapSettings(mapState.settings)); - } - } - - let isLayerTOCOpen = DEFAULT_IS_LAYER_TOC_OPEN; - if (_.has(this.input, 'isLayerTOCOpen')) { - isLayerTOCOpen = this.input.isLayerTOCOpen; - } else if (this._attributes?.uiStateJSON) { - const uiState = JSON.parse(this._attributes.uiStateJSON); - if ('isLayerTOCOpen' in uiState) { - isLayerTOCOpen = uiState.isLayerTOCOpen; - } - } - this._store.dispatch(setIsLayerTOCOpen(isLayerTOCOpen)); - - let openTOCDetails = []; - if (_.has(this.input, 'openTOCDetails')) { - openTOCDetails = this.input.openTOCDetails; - } else if (this._attributes?.uiStateJSON) { - const uiState = JSON.parse(this._attributes.uiStateJSON); - if ('openTOCDetails' in uiState) { - openTOCDetails = uiState.openTOCDetails; - } - } - this._store.dispatch(setOpenTOCDetails(openTOCDetails)); + const store = this._savedMap.getStore(); + store.dispatch(setReadOnly(true)); + store.dispatch(disableScrollZoom()); if (_.has(this.input, 'disableInteractive') && this.input.disableInteractive) { - this._store.dispatch(disableInteractive()); + store.dispatch(disableInteractive()); } if (_.has(this.input, 'disableTooltipControl') && this.input.disableTooltipControl) { - this._store.dispatch(disableTooltipControl()); + store.dispatch(disableTooltipControl()); } if (_.has(this.input, 'hideToolbarOverlay') && this.input.hideToolbarOverlay) { - this._store.dispatch(hideToolbarOverlay()); + store.dispatch(hideToolbarOverlay()); } if (_.has(this.input, 'hideLayerControl') && this.input.hideLayerControl) { - this._store.dispatch(hideLayerControl()); + store.dispatch(hideLayerControl()); } if (_.has(this.input, 'hideViewControl') && this.input.hideViewControl) { - this._store.dispatch(hideViewControl()); - } - - if (this.input.mapCenter) { - this._store.dispatch( - setGotoWithCenter({ - lat: this.input.mapCenter.lat, - lon: this.input.mapCenter.lon, - zoom: this.input.mapCenter.zoom, - }) - ); - } else if (this._attributes?.mapStateJSON) { - const mapState = JSON.parse(this._attributes.mapStateJSON); - this._store.dispatch( - setGotoWithCenter({ - lat: mapState.center.lat, - lon: mapState.center.lon, - zoom: mapState.zoom, - }) - ); + store.dispatch(hideViewControl()); } - const layerList = getInitialLayers(this._attributes.layerListJSON); - this.setLayerList(layerList); - if (this.input.hiddenLayers) { - this._store.dispatch(setHiddenLayers(this.input.hiddenLayers)); - } this._dispatchSetQuery(this.input); this._dispatchSetRefreshConfig(this.input); - this._unsubscribeFromStore = this._store.subscribe(() => { + this._unsubscribeFromStore = this._savedMap.getStore().subscribe(() => { this._handleStoreChanges(); }); } @@ -226,26 +171,27 @@ export class MapEmbeddable title, editPath: `/${MAP_PATH}/${savedObjectId}`, editUrl: getHttp().basePath.prepend(getExistingMapPath(savedObjectId)), + indexPatterns: await this.getIndexPatterns(), }); } public inputIsRefType( input: MapByValueInput | MapByReferenceInput ): input is MapByReferenceInput { - return attributeService.inputIsRefType(input); + return getMapAttributeService().inputIsRefType(input); } public async getInputAsRefType(): Promise { - const input = attributeService.getExplicitInputFromEmbeddable(this); - return attributeService.getInputAsRefType(input, { + const input = getMapAttributeService().getExplicitInputFromEmbeddable(this); + return getMapAttributeService().getInputAsRefType(input, { showSaveModal: true, saveModalTitle: this.getTitle(), }); } public async getInputAsValueType(): Promise { - const input = attributeService.getExplicitInputFromEmbeddable(this); - return attributeService.getInputAsValueType(input); + const input = getMapAttributeService().getExplicitInputFromEmbeddable(this); + return getMapAttributeService().getInputAsValueType(input); } public getDescription() { @@ -261,11 +207,11 @@ export class MapEmbeddable }; setEventHandlers = (eventHandlers: EventHandlers) => { - this._store.dispatch(setEventHandlers(eventHandlers)); + this._savedMap.getStore().dispatch(setEventHandlers(eventHandlers)); }; getInspectorAdapters() { - return getInspectorAdapters(this._store.getState()); + return getInspectorAdapters(this._savedMap.getStore().getState()); } onContainerStateChanged(containerState: MapEmbeddableInput) { @@ -296,7 +242,7 @@ export class MapEmbeddable this._prevTimeRange = timeRange; this._prevQuery = query; this._prevFilters = filters; - this._store.dispatch( + this._savedMap.getStore().dispatch( setQuery({ filters: filters.filter((filter) => !filter.meta.disabled), query, @@ -308,7 +254,7 @@ export class MapEmbeddable _dispatchSetRefreshConfig({ refreshConfig }: Pick) { this._prevRefreshConfig = refreshConfig; - this._store.dispatch( + this._savedMap.getStore().dispatch( setRefreshConfig({ isPaused: refreshConfig.pause, interval: refreshConfig.value, @@ -330,7 +276,7 @@ export class MapEmbeddable const I18nContext = getCoreI18n().Context; render( - + (replaceLayerList(layerList)); - } - - private async setIndexPatterns(layerList: LayerDescriptor[]) { - let queryableIndexPatternIds: string[]; - try { - const tempStore = createMapStore(); - layerList.forEach((layerDescriptor: LayerDescriptor) => { - tempStore.dispatch(addLayerWithoutDataSync(layerDescriptor)); + this._savedMap.getStore().dispatch(replaceLayerList(layerList)); + this.getIndexPatterns().then((indexPatterns) => { + this.updateOutput({ + ...this.getOutput(), + indexPatterns, }); - queryableIndexPatternIds = getQueryableUniqueIndexPatternIds(tempStore.getState()); - } catch (error) { - throw new Error( - i18n.translate('xpack.maps.mapEmbeddable.invalidLayerList', { - defaultMessage: 'Unable to set map embeddable layer list, invalid layer list', - }) - ); - } - const indexPatterns = await getIndexPatternsFromIds(queryableIndexPatternIds); - this.updateOutput({ - ...this.getOutput(), - indexPatterns, }); } + private async getIndexPatterns() { + const queryableIndexPatternIds = getQueryableUniqueIndexPatternIds( + this._savedMap.getStore().getState() + ); + return await getIndexPatternsFromIds(queryableIndexPatternIds); + } + addFilters = async (filters: Filter[], actionId: string = ACTION_GLOBAL_APPLY_FILTER) => { const executeContext = { ...this.getActionContext(), @@ -428,8 +364,8 @@ export class MapEmbeddable } _handleStoreChanges() { - const center = getMapCenter(this._store.getState()); - const zoom = getMapZoom(this._store.getState()); + const center = getMapCenter(this._savedMap.getStore().getState()); + const zoom = getMapZoom(this._savedMap.getStore().getState()); const mapCenter = this.input.mapCenter || undefined; if ( @@ -447,21 +383,21 @@ export class MapEmbeddable }); } - const isLayerTOCOpen = getIsLayerTOCOpen(this._store.getState()); + const isLayerTOCOpen = getIsLayerTOCOpen(this._savedMap.getStore().getState()); if (this.input.isLayerTOCOpen !== isLayerTOCOpen) { this.updateInput({ isLayerTOCOpen, }); } - const openTOCDetails = getOpenTOCDetails(this._store.getState()); + const openTOCDetails = getOpenTOCDetails(this._savedMap.getStore().getState()); if (!_.isEqual(this.input.openTOCDetails, openTOCDetails)) { this.updateInput({ openTOCDetails, }); } - const hiddenLayerIds = getHiddenLayerIds(this._store.getState()); + const hiddenLayerIds = getHiddenLayerIds(this._savedMap.getStore().getState()); if (!_.isEqual(this.input.hiddenLayers, hiddenLayerIds)) { this.updateInput({ diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts similarity index 78% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts rename to x-pack/plugins/maps/public/map_attribute_service.ts index 96194f1030e3b..44cb775819d55 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -4,21 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AttributeService } from '../../../../../../../src/plugins/embeddable/public'; -import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -import { MapByValueInput, MapByReferenceInput } from '../../../embeddable/types'; -import { - checkForDuplicateTitle, - OnSaveProps, -} from '../../../../../../../src/plugins/saved_objects/public'; -import { - getCoreOverlays, - getEmbeddableService, - getSavedObjectsClient, -} from '../../../kibana_services'; +import { AttributeService } from '../../../../src/plugins/embeddable/public'; +import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; +import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; +import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; +import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; // @ts-expect-error -import { extractReferences, injectReferences } from '../../../../common/migrations/references'; +import { extractReferences, injectReferences } from '../common/migrations/references'; +import { MapByValueInput, MapByReferenceInput } from '.embeddable/types'; export type MapAttributeService = AttributeService< MapSavedObjectAttributes, diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx index f469e01da1380..6addcbfbf326d 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx @@ -50,6 +50,7 @@ import { goToSpecifiedPath } from '../../render_app'; import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; import { getExistingMapPath } from '../../../common/constants'; import { + getInitialLayersFromUrlParam, getInitialQuery, getInitialRefreshConfig, getInitialTimeFilters, @@ -309,7 +310,10 @@ export class MapApp extends React.Component { async _initMap() { let mapSavedObjectAttributes; try { - mapSavedObjectAttributes = await this.props.savedMap.loadAttributes(); + const overrides = { + defaultLayers: getInitialLayersFromUrlParam(), + }; + mapSavedObjectAttributes = await this.props.savedMap.loadAttributes(overrides); } catch (err) { if (this._isMounted) { getToasts().addWarning({ diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts index 287522bb22145..e9347dd986da7 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts @@ -5,6 +5,7 @@ */ export { SavedMap } from './saved_map'; +export { getInitialLayersFromUrlParam } from './get_initial_layers'; export { getInitialQuery } from './get_initial_query'; export { getInitialRefreshConfig } from './get_initial_refresh_config'; export { getInitialTimeFilters } from './get_initial_time_filters'; diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index 9772598c05f53..03a2f0bc406c7 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -27,9 +27,10 @@ import { replaceLayerList, setIsLayerTOCOpen, setOpenTOCDetails, + setHiddenLayers, } from '../../../actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; -import { getMapAttributeService } from './map_attribute_service'; +import { getMapAttributeService } from '../../../map_attribute_service'; import { checkForDuplicateTitle, OnSaveProps, @@ -54,7 +55,7 @@ export class SavedMap { private _initialLayerListConfig: LayerDescriptor[] = []; private readonly _mapEmbeddableInput?: MapEmbeddableInput; private _originatingApp?: string; - private readonly _stateTransfer: EmbeddableStateTransfer; + private readonly _stateTransfer?: EmbeddableStateTransfer; private readonly _store: MapStore; constructor({ @@ -66,7 +67,7 @@ export class SavedMap { mapEmbeddableInput?: MapEmbeddableInput; embeddableId?: string; originatingApp?: string; - stateTransfer: EmbeddableStateTransfer; + stateTransfer?: EmbeddableStateTransfer; }) { this._mapEmbeddableInput = mapEmbeddableInput; this._embeddableId = embeddableId; @@ -79,7 +80,13 @@ export class SavedMap { return this._store; } - async loadAttributes() { + async loadAttributes(overrides?: { + isLayerTOCOpen?: boolean; + openTOCDetails?: string[]; + mapCenter?: MapCenterAndZoom; + hiddenLayers?: string[]; + defaultLayers?: LayerDescriptor[]; + }) { if (!this._mapEmbeddableInput) { this._attributes = { title: i18n.translate('xpack.maps.newMapTitle', { @@ -91,14 +98,44 @@ export class SavedMap { this._attributes = await getMapAttributeService().unwrapAttributes(this._mapEmbeddableInput); } - const layerList = getInitialLayers( - this._attributes.layerListJSON, - getInitialLayersFromUrlParam() - ); - this._store.dispatch(replaceLayerList(layerList)); - this._initialLayerListConfig = copyPersistentState(layerList); + if (this._attributes?.mapStateJSON) { + const mapState = JSON.parse(this._attributes.mapStateJSON); + if (mapState.settings) { + this._store.dispatch(setMapSettings(mapState.settings)); + } + } + + let isLayerTOCOpen = DEFAULT_IS_LAYER_TOC_OPEN; + if (overrides && overrides.isLayerTOCOpen !== undefined) { + isLayerTOCOpen = overrides.isLayerTOCOpen; + } else if (this._attributes?.uiStateJSON) { + const uiState = JSON.parse(this._attributes.uiStateJSON); + if ('isLayerTOCOpen' in uiState) { + isLayerTOCOpen = uiState.isLayerTOCOpen; + } + } + this._store.dispatch(setIsLayerTOCOpen(isLayerTOCOpen)); + + let openTOCDetails = []; + if (overrides && overrides.openTOCDetails !== undefined) { + openTOCDetails = overrides.openTOCDetails; + } else if (this._attributes?.uiStateJSON) { + const uiState = JSON.parse(this._attributes.uiStateJSON); + if ('openTOCDetails' in uiState) { + openTOCDetails = uiState.openTOCDetails; + } + } + this._store.dispatch(setOpenTOCDetails(openTOCDetails)); - if (this._attributes.mapStateJSON) { + if (overrides && overrides.mapCenter !== undefined) { + this._store.dispatch( + setGotoWithCenter({ + lat: overrides.mapCenter.lat, + lon: overrides.mapCenter.lon, + zoom: overrides.mapCenter.zoom, + }) + ); + } else if (this._attributes?.mapStateJSON) { const mapState = JSON.parse(this._attributes.mapStateJSON); this._store.dispatch( setGotoWithCenter({ @@ -107,18 +144,17 @@ export class SavedMap { zoom: mapState.zoom, }) ); - if (mapState.settings) { - this._store.dispatch(setMapSettings(mapState.settings)); - } } - if (this._attributes.uiStateJSON) { - const uiState = JSON.parse(this._attributes.uiStateJSON); - this._store.dispatch( - setIsLayerTOCOpen(_.get(uiState, 'isLayerTOCOpen', DEFAULT_IS_LAYER_TOC_OPEN)) - ); - this._store.dispatch(setOpenTOCDetails(_.get(uiState, 'openTOCDetails', []))); + const layerList = getInitialLayers( + this._attributes.layerListJSON, + overrides && overrides.defaultLayers !== undefined ? overrides.defaultLayers : [] + ); + this._store.dispatch(replaceLayerList(layerList)); + if (overrides && overrides.hiddenLayers !== undefined) { + this._store.dispatch(setHiddenLayers(overrides.hiddenLayers)); } + this._initialLayerListConfig = copyPersistentState(layerList); return this._attributes; } @@ -142,6 +178,14 @@ export class SavedMap { !_.isEqual(JSON.parse(JSON.stringify(layerListConfigOnly)), savedLayerList); }; + private _getStateTransfer() { + if (!this._stateTransfer) { + throw new Error('stateTransfer not provided in constructor'); + } + + return this._stateTransfer; + } + setBreadcrumbs() { if (!this._attributes) { throw new Error('Invalid usage, must await loadAttributes before calling hasUnsavedChanges'); @@ -151,7 +195,7 @@ export class SavedMap { title: this._attributes.title, getHasUnsavedChanges: this.hasUnsavedChanges, originatingApp: this._originatingApp, - getAppNameFromId: this._stateTransfer.getAppNameFromId, + getAppNameFromId: this._getStateTransfer().getAppNameFromId, }); getCoreChrome().setBreadcrumbs(breadcrumbs); } @@ -165,7 +209,7 @@ export class SavedMap { } public getAppNameFromId = (appId: string): string | undefined => { - return this._stateTransfer.getAppNameFromId(appId); + return this._getStateTransfer().getAppNameFromId(appId); }; public hasSaveAndReturnConfig() { @@ -253,7 +297,7 @@ export class SavedMap { }); return; } - this._stateTransfer.navigateToWithEmbeddablePackage(this._originatingApp, { + this._getStateTransfer().navigateToWithEmbeddablePackage(this._originatingApp, { state: { embeddableId: newCopyOnSave ? undefined : this._embeddableId, type: MAP_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 4b5122050eb71..ffe5cb67d663a 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -365,13 +365,25 @@ export const getUniqueIndexPatternIds = createSelector(getLayerList, (layerList) }); // Get list of unique index patterns, excluding index patterns from layers that disable applyGlobalQuery -export const getQueryableUniqueIndexPatternIds = createSelector(getLayerList, (layerList) => { - const indexPatternIds: string[] = []; - layerList.forEach((layer) => { - indexPatternIds.push(...layer.getQueryableIndexPatternIds()); - }); - return _.uniq(indexPatternIds); -}); +export const getQueryableUniqueIndexPatternIds = createSelector( + getLayerList, + getWaitingForMapReadyLayerListRaw, + (layerList, waitingForMapReadyLayerList) => { + const indexPatternIds: string[] = []; + + if (waitingForMapReadyLayerList.length) { + waitingForMapReadyLayerList.forEach((layerDescriptor) => { + const layer = createLayerInstance(layerDescriptor); + indexPatternIds.push(...layer.getQueryableIndexPatternIds()); + }); + } else { + layerList.forEach((layer) => { + indexPatternIds.push(...layer.getQueryableIndexPatternIds()); + }); + } + return _.uniq(indexPatternIds); + } +); export const hasDirtyState = createSelector(getLayerListRaw, (layerListRaw) => { return layerListRaw.some((layerDescriptor) => { From 4c9de954debbd64363ace52ce274e8c800247ccb Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 07:49:31 -0700 Subject: [PATCH 18/35] clean up --- x-pack/plugins/maps/public/embeddable/map_embeddable.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index bbe1b28443be3..7ac61b3a5d05b 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -161,7 +161,9 @@ export class MapEmbeddable } private async initializeOutput() { - const savedMapTitle = this._attributes?.title ? this._attributes.title : ''; + const savedMapTitle = this._savedMap.getAttributes()?.title + ? this._savedMap.getAttributes().title + : ''; const input = this.getInput(); const title = input.hidePanelTitles ? '' : input.title || savedMapTitle; const savedObjectId = (input as MapByReferenceInput).savedObjectId; @@ -195,7 +197,7 @@ export class MapEmbeddable } public getDescription() { - return this._attributes?.description; + return this._savedMap.getAttributes()?.description; } public supportedTriggers(): Array { From 6128b0df8ee838c8b79f389716f74124d575bde3 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 07:55:43 -0700 Subject: [PATCH 19/35] restore imports --- .../public/routes/map_app/saved_map/get_initial_layers.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts index f7d42dbbeab96..b890b5f6d8fa4 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts @@ -7,6 +7,13 @@ import _ from 'lodash'; import rison from 'rison-node'; import { i18n } from '@kbn/i18n'; +import '../../../classes/sources/wms_source'; +import '../../../classes/sources/ems_file_source'; +import '../../../classes/sources/es_search_source'; +import '../../../classes/sources/es_pew_pew_source'; +import '../../../classes/sources/kibana_regionmap_source'; +import '../../../classes/sources/es_geo_grid_source'; +import '../../../classes/sources/xyz_tms_source'; import { LayerDescriptor } from '../../../../common/descriptor_types'; // @ts-expect-error import { KibanaTilemapSource } from '../../../classes/sources/kibana_tilemap_source'; @@ -23,6 +30,7 @@ export function getInitialLayers(layerListJSON?: string, initialLayers: LayerDes if (layerListJSON) { return JSON.parse(layerListJSON); } + const tilemapSourceFromKibana = getKibanaTileMap(); if (_.get(tilemapSourceFromKibana, 'url')) { const layerDescriptor = TileLayer.createDescriptor({ From b4005c90199b902305cc0ffa658ed7d46d4a3d74 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 09:28:46 -0700 Subject: [PATCH 20/35] clean up breadcrumbs to match lens --- .../saved_map/get_breadcrumbs.test.tsx | 7 ++-- .../map_app/saved_map/get_breadcrumbs.tsx | 32 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx index 202e9350b4fe0..7064663445fae 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx @@ -20,7 +20,7 @@ test('should get breadcrumbs "Maps / mymap"', () => { expect(breadcrumbs[1].text).toBe('mymap'); }); -test('should get breadcrumbs "Dashboard / Maps / mymap" with originatingApp', () => { +test('should get breadcrumbs "Dashboard / mymap" with originatingApp', () => { const breadcrumbs = getBreadcrumbs({ title: 'mymap', getHasUnsavedChanges, @@ -29,8 +29,7 @@ test('should get breadcrumbs "Dashboard / Maps / mymap" with originatingApp', () return 'Dashboard'; }, }); - expect(breadcrumbs.length).toBe(3); + expect(breadcrumbs.length).toBe(2); expect(breadcrumbs[0].text).toBe('Dashboard'); - expect(breadcrumbs[1].text).toBe('Maps'); - expect(breadcrumbs[2].text).toBe('mymap'); + expect(breadcrumbs[1].text).toBe('mymap'); }); diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx index 4def1f33334b2..30eac5c1b4546 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx @@ -39,24 +39,24 @@ export function getBreadcrumbs({ }, text: getAppNameFromId(originatingApp), }); - } - - breadcrumbs.push({ - text: getAppTitle(), - onClick: async () => { - if (getHasUnsavedChanges()) { - const confirmed = await getCoreOverlays().openConfirm(unsavedChangesWarning, { - title: unsavedChangesTitle, - 'data-test-subj': 'appLeaveConfirmModal', - }); - if (confirmed) { + } else { + breadcrumbs.push({ + text: getAppTitle(), + onClick: async () => { + if (getHasUnsavedChanges()) { + const confirmed = await getCoreOverlays().openConfirm(unsavedChangesWarning, { + title: unsavedChangesTitle, + 'data-test-subj': 'appLeaveConfirmModal', + }); + if (confirmed) { + goToSpecifiedPath('/'); + } + } else { goToSpecifiedPath('/'); } - } else { - goToSpecifiedPath('/'); - } - }, - }); + }, + }); + } breadcrumbs.push({ text: title }); From 2b86ce2b4a6d5104d851f9ea507905b80bdafa43 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 10:49:44 -0700 Subject: [PATCH 21/35] fix check for duplicate title --- x-pack/plugins/maps/common/i18n_getters.ts | 2 +- .../embeddable/map_embeddable_factory.ts | 4 +- .../maps/public/map_attribute_service.ts | 5 ++- .../routes/map_app/saved_map/saved_map.ts | 37 ++----------------- .../public/routes/map_app/top_nav_config.tsx | 31 +++++++++++++++- 5 files changed, 40 insertions(+), 39 deletions(-) diff --git a/x-pack/plugins/maps/common/i18n_getters.ts b/x-pack/plugins/maps/common/i18n_getters.ts index d0582bf5c2971..a128038e321fc 100644 --- a/x-pack/plugins/maps/common/i18n_getters.ts +++ b/x-pack/plugins/maps/common/i18n_getters.ts @@ -15,7 +15,7 @@ export function getAppTitle() { }); } -export function getMapEmbeddableTitle() { +export function getMapEmbeddableDisplayName() { return i18n.translate('xpack.maps.embeddableDisplayName', { defaultMessage: 'map', }); diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts index 7e52d033debe6..dcd54fc4a8693 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -12,7 +12,7 @@ import { import '../index.scss'; import { MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; import { LayerDescriptor } from '../../common/descriptor_types'; -import { getMapEmbeddableTitle } from '../../common/i18n_getters'; +import { getMapEmbeddableDisplayName } from '../../common/i18n_getters'; import { MapByValueInput, MapByReferenceInput, MapEmbeddableInput } from './types'; import { lazyLoadMapModules } from '../lazy_load_bundle'; @@ -37,7 +37,7 @@ export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { } getDisplayName() { - return getMapEmbeddableTitle(); + return getMapEmbeddableDisplayName(); } createFromSavedObject = async ( diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index 44cb775819d55..f88ec81ea8478 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -7,11 +7,12 @@ import { AttributeService } from '../../../../src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; +import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters'; import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; // @ts-expect-error import { extractReferences, injectReferences } from '../common/migrations/references'; -import { MapByValueInput, MapByReferenceInput } from '.embeddable/types'; +import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; export type MapAttributeService = AttributeService< MapSavedObjectAttributes, @@ -66,7 +67,7 @@ export function getMapAttributeService(): MapAttributeService { copyOnSave: false, lastSavedTitle: '', getEsType: () => MAP_SAVED_OBJECT_TYPE, - getDisplayName: () => MAP_SAVED_OBJECT_TYPE, + getDisplayName: () => getMapEmbeddableDisplayName, }, props.isTitleDuplicateConfirmed, props.onTitleDuplicate, diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index 03a2f0bc406c7..1ba14ddc625c9 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -8,7 +8,6 @@ import { i18n } from '@kbn/i18n'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -import { getMapEmbeddableTitle } from '../../../../common/i18n_getters'; import { createMapStore, MapStore, MapStoreState } from '../../../reducers/store'; import { getTimeFilters, @@ -31,10 +30,7 @@ import { } from '../../../actions'; import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_selectors'; import { getMapAttributeService } from '../../../map_attribute_service'; -import { - checkForDuplicateTitle, - OnSaveProps, -} from '../../../../../../../src/plugins/saved_objects/public'; +import { OnSaveProps } from '../../../../../../../src/plugins/saved_objects/public'; import { MapByReferenceInput, MapEmbeddableInput } from '../../../embeddable/types'; import { getCoreChrome, @@ -53,7 +49,7 @@ export class SavedMap { private _attributes: MapSavedObjectAttributes | null = null; private readonly _embeddableId?: string; private _initialLayerListConfig: LayerDescriptor[] = []; - private readonly _mapEmbeddableInput?: MapEmbeddableInput; + private _mapEmbeddableInput?: MapEmbeddableInput; private _originatingApp?: string; private readonly _stateTransfer?: EmbeddableStateTransfer; private readonly _store: MapStore; @@ -228,8 +224,6 @@ export class SavedMap { newDescription, newTitle, newCopyOnSave, - isTitleDuplicateConfirmed, - onTitleDuplicate, returnToOrigin, saveByReference, }: OnSaveProps & { @@ -240,30 +234,6 @@ export class SavedMap { throw new Error('Invalid usage, must await loadAttributes before calling save'); } - if (saveByReference) { - try { - await checkForDuplicateTitle( - { - id: newCopyOnSave ? undefined : this.getSavedObjectId(), - title: newTitle, - copyOnSave: newCopyOnSave, - lastSavedTitle: this._attributes.title, - getEsType: () => MAP_SAVED_OBJECT_TYPE, - getDisplayName: getMapEmbeddableTitle, - }, - isTitleDuplicateConfirmed, - onTitleDuplicate, - { - savedObjectsClient: getSavedObjectsClient(), - overlays: getCoreOverlays(), - } - ); - } catch (e) { - // ignore duplicate title failure, user notified in save modal - return; - } - } - const prevTitle = this._attributes.title; const prevDescription = this._attributes.description; this._attributes.title = newTitle; @@ -307,6 +277,7 @@ export class SavedMap { return; } + this._mapEmbeddableInput = updatedMapEmbeddableInput; // break connection to originating application this._originatingApp = undefined; getToasts().addSuccess({ @@ -318,7 +289,7 @@ export class SavedMap { getCoreChrome().docTitle.change(newTitle); this.setBreadcrumbs(); - goToSpecifiedPath(`/map/${updatedMapEmbeddableInput.savedObjectId}${window.location.hash}`); + goToSpecifiedPath(`/map/${this.getSavedObjectId()}${window.location.hash}`); return; } diff --git a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx index c4ce2bbee553c..faf9ef3a8ec05 100644 --- a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx @@ -15,8 +15,11 @@ import { getCoreI18n, getNavigateToApp, getIsAllowByValueEmbeddables, + getSavedObjectsClient, + getCoreOverlays, } from '../../kibana_services'; import { + checkForDuplicateTitle, SavedObjectSaveModalOrigin, OnSaveProps, showSaveModal, @@ -25,6 +28,7 @@ import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; import { goToSpecifiedPath } from '../../render_app'; import { SavedMap } from './saved_map'; import { EmbeddableStateTransfer } from '../../../../../../src/plugins/embeddable/public'; +import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters'; function getSaveAndReturnButtonLabel() { return getIsAllowByValueEmbeddables() @@ -133,11 +137,36 @@ export function getTopNavConfig({ originatingApp={savedMap.getOriginatingApp()} getAppNameFromId={savedMap.getAppNameFromId} onSave={async (props: OnSaveProps & { returnToOrigin: boolean }) => { + try { + await checkForDuplicateTitle( + { + id: props.newCopyOnSave ? undefined : savedMap.getSavedObjectId(), + title: props.newTitle, + copyOnSave: props.newCopyOnSave, + lastSavedTitle: + savedMap.getSavedObjectId() && savedMap.getAttributes() + ? savedMap.getAttributes().title + : undefined, + getEsType: () => MAP_SAVED_OBJECT_TYPE, + getDisplayName: getMapEmbeddableDisplayName, + }, + props.isTitleDuplicateConfirmed, + props.onTitleDuplicate, + { + savedObjectsClient: getSavedObjectsClient(), + overlays: getCoreOverlays(), + } + ); + } catch (e) { + // ignore duplicate title failure, user notified in save modal + return {}; + } + await savedMap.save({ ...props, saveByReference: true, }); - // showSaveModal wrapper requires onSave to return an object with an id to close the modal after save + // showSaveModal wrapper requires onSave to return an object with an id to close the modal after successful save return { id: 'id' }; }} onClose={() => {}} From f6df791f967fed870a712aa0d3330e5a58735393 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 13:00:29 -0700 Subject: [PATCH 22/35] tslint --- .../VisitorBreakdownMap/EmbeddedMap.tsx | 1 + .../functions/external/saved_map.ts | 1 + .../input_type_to_expression/map.test.ts | 1 + .../maps/public/embeddable/map_embeddable.tsx | 44 ++++++++++++------- .../embeddable/map_embeddable_factory.ts | 3 +- .../plugins/maps/public/embeddable/types.ts | 25 ++++++----- .../maps/public/lazy_load_bundle/index.ts | 5 +-- .../maps/public/map_attribute_service.ts | 4 +- x-pack/plugins/maps/public/render_app.tsx | 7 ++- .../public/routes/list/maps_list_view.tsx | 4 +- .../maps/public/routes/map_app/map_app.tsx | 15 ++----- .../routes/map_app/map_app_connector.ts | 8 +--- .../routes/map_app/map_app_container.tsx | 9 ++-- .../routes/map_app/saved_map/saved_map.ts | 35 ++++++++------- .../public/routes/map_app/top_nav_config.tsx | 14 ++---- .../public/routes/map_app/url_state/index.ts | 2 +- .../embeddables/embedded_map_helpers.tsx | 3 +- .../translations/translations/ja-JP.json | 3 -- .../translations/translations/zh-CN.json | 3 -- .../location_map/embeddables/embedded_map.tsx | 3 +- 20 files changed, 95 insertions(+), 95 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx index 77afe92a8f521..6d476dd1aaa48 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx @@ -77,6 +77,7 @@ export function EmbeddedMapComponent() { ); const input: MapEmbeddableInput = { + attributes: {}, id: uuid.v4(), filters: mapFilters, refreshConfig: { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts index a64ff7da2aa19..67b31cbb1ffba 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts @@ -83,6 +83,7 @@ export function savedMap(): ExpressionFunctionDefinition< return { type: EmbeddableExpressionType, input: { + attributes: {}, id: args.id, filters: getQueryFilters(filters), timeRange: args.timerange || defaultTimeRange, diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts index d2c803a1ff208..acfe8d44f38a5 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts @@ -9,6 +9,7 @@ import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embedd import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseSavedMapInput = { + attributes: {}, id: 'embeddableId', filters: [], isLayerTOCOpen: false, diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 7ac61b3a5d05b..215f57f68db16 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -10,7 +10,6 @@ import { Provider } from 'react-redux'; import { render, unmountComponentAtNode } from 'react-dom'; import { Subscription } from 'rxjs'; import { Unsubscribe } from 'redux'; -import { i18n } from '@kbn/i18n'; import { Embeddable, IContainer, @@ -29,9 +28,7 @@ import { Query, RefreshInterval, } from '../../../../../src/plugins/data/public'; -import { MapSettings } from '../reducers/map'; import { - addLayerWithoutDataSync, replaceLayerList, setQuery, setRefreshConfig, @@ -54,7 +51,6 @@ import { getMapZoom, getHiddenLayerIds, getQueryableUniqueIndexPatternIds, - getLayerListRaw, } from '../selectors/map_selectors'; import { APP_ID, @@ -65,11 +61,9 @@ import { import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; -import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; import { MapContainer } from '../connected_components/map_container'; import { SavedMap } from '../routes/map_app/saved_map'; import { getIndexPatternsFromIds } from '../index_pattern_util'; -import { DEFAULT_IS_LAYER_TOC_OPEN } from '../reducers/ui'; import { getMapAttributeService } from '../map_attribute_service'; import { @@ -103,6 +97,7 @@ export class MapEmbeddable { editApp: APP_ID, editable: config.editable, + indexPatterns: [], }, parent ); @@ -152,8 +147,15 @@ export class MapEmbeddable store.dispatch(hideViewControl()); } - this._dispatchSetQuery(this.input); - this._dispatchSetRefreshConfig(this.input); + this._dispatchSetQuery({ + query: this.input.query, + timeRange: this.input.timeRange, + filters: this.input.filters, + forceRefresh: false, + }); + if (this.input.refreshConfig) { + this._dispatchSetRefreshConfig(this.input.refreshConfig); + } this._unsubscribeFromStore = this._savedMap.getStore().subscribe(() => { this._handleStoreChanges(); @@ -197,7 +199,7 @@ export class MapEmbeddable } public getDescription() { - return this._savedMap.getAttributes()?.description; + return this._isInitialized ? this._savedMap.getAttributes().description : ''; } public supportedTriggers(): Array { @@ -222,24 +224,32 @@ export class MapEmbeddable !_.isEqual(containerState.query, this._prevQuery) || !esFilters.onlyDisabledFiltersChanged(containerState.filters, this._prevFilters) ) { - this._dispatchSetQuery(containerState); + this._dispatchSetQuery({ + query: containerState.query, + timeRange: containerState.timeRange, + filters: containerState.filters, + forceRefresh: false, + }); } - if (!_.isEqual(containerState.refreshConfig, this._prevRefreshConfig)) { - this._dispatchSetRefreshConfig(containerState); + if ( + containerState.refreshConfig && + !_.isEqual(containerState.refreshConfig, this._prevRefreshConfig) + ) { + this._dispatchSetRefreshConfig(containerState.refreshConfig); } } _dispatchSetQuery({ query, timeRange, - filters, + filters = [], forceRefresh, }: { query?: Query; timeRange?: TimeRange; - filters: Filter[]; - forceRefresh?: boolean; + filters?: Filter[]; + forceRefresh: boolean; }) { this._prevTimeRange = timeRange; this._prevQuery = query; @@ -254,7 +264,7 @@ export class MapEmbeddable ); } - _dispatchSetRefreshConfig({ refreshConfig }: Pick) { + _dispatchSetRefreshConfig(refreshConfig: RefreshInterval) { this._prevRefreshConfig = refreshConfig; this._savedMap.getStore().dispatch( setRefreshConfig({ @@ -286,7 +296,7 @@ export class MapEmbeddable getActionContext={this.getActionContext} renderTooltipContent={this._renderTooltipContent} title={this.getTitle()} - description={this._description} + description={this.getDescription()} /> , diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts index dcd54fc4a8693..616da46b346db 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts @@ -11,9 +11,8 @@ import { } from '../../../../../src/plugins/embeddable/public'; import '../index.scss'; import { MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; -import { LayerDescriptor } from '../../common/descriptor_types'; import { getMapEmbeddableDisplayName } from '../../common/i18n_getters'; -import { MapByValueInput, MapByReferenceInput, MapEmbeddableInput } from './types'; +import { MapByReferenceInput, MapEmbeddableInput } from './types'; import { lazyLoadMapModules } from '../lazy_load_bundle'; export class MapEmbeddableFactory implements EmbeddableFactoryDefinition { diff --git a/x-pack/plugins/maps/public/embeddable/types.ts b/x-pack/plugins/maps/public/embeddable/types.ts index baa4de34dedc2..a401cafcff8ea 100644 --- a/x-pack/plugins/maps/public/embeddable/types.ts +++ b/x-pack/plugins/maps/public/embeddable/types.ts @@ -5,16 +5,20 @@ */ import { IIndexPattern } from '../../../../../src/plugins/data/common/index_patterns'; -import { MapSettings } from '../reducers/map'; -import { EmbeddableInput, EmbeddableOutput, SavedObjectEmbeddableInput } from '../../../../../src/plugins/embeddable/public'; -import { Filter, Query, RefreshInterval, TimeRange } from '../../../../../src/plugins/data/common'; -import { LayerDescriptor, MapCenterAndZoom } from '../../common/descriptor_types'; +import { + EmbeddableInput, + EmbeddableOutput, + SavedObjectEmbeddableInput, +} from '../../../../../src/plugins/embeddable/public'; +import { RefreshInterval } from '../../../../../src/plugins/data/common'; +import { MapCenterAndZoom } from '../../common/descriptor_types'; +import { MapSavedObjectAttributes } from '../../common/map_saved_object_type'; -export type MapEmbeddableConfig = { +export interface MapEmbeddableConfig { editable: boolean; -}; +} -type MapEmbeddableState = { +interface MapEmbeddableState { refreshConfig?: RefreshInterval; isLayerTOCOpen?: boolean; openTOCDetails?: string[]; @@ -26,13 +30,14 @@ type MapEmbeddableState = { mapCenter?: MapCenterAndZoom; hiddenLayers?: string[]; hideFilterActions?: boolean; -}; +} export type MapByValueInput = { attributes: MapSavedObjectAttributes; -} & EmbeddableInput & MapEmbeddableState; +} & EmbeddableInput & + MapEmbeddableState; export type MapByReferenceInput = SavedObjectEmbeddableInput & MapEmbeddableState; export type MapEmbeddableInput = MapByValueInput | MapByReferenceInput; export type MapEmbeddableOutput = EmbeddableOutput & { indexPatterns: IIndexPattern[]; -} +}; diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts index 30f9c1d7838cd..6795fbebbd86a 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts @@ -4,14 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AnyAction } from 'redux'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { IndexPatternsContract } from 'src/plugins/data/public/index_patterns'; import { AppMountParameters } from 'kibana/public'; -import { IndexPattern } from 'src/plugins/data/public'; import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public'; import { LayerDescriptor } from '../../common/descriptor_types'; -import { MapStore, MapStoreState } from '../reducers/store'; import { MapEmbeddableConfig, MapEmbeddableInput, MapEmbeddableOutput } from '../embeddable/types'; import { SourceRegistryEntry } from '../classes/sources/source_registry'; import { LayerWizard } from '../classes/layers/layer_wizard_registry'; @@ -22,7 +19,7 @@ interface LazyLoadedMapModules { MapEmbeddable: new ( config: MapEmbeddableConfig, initialInput: MapEmbeddableInput, - parent?: IContainer, + parent?: IContainer ) => Embeddable; getIndexPatternService: () => IndexPatternsContract; getMapsCapabilities: () => any; diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index f88ec81ea8478..2bb5e07e4ad07 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -7,7 +7,7 @@ import { AttributeService } from '../../../../src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../common/map_saved_object_type'; import { MAP_SAVED_OBJECT_TYPE } from '../common/constants'; -import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters'; +import { getMapEmbeddableDisplayName } from '../common/i18n_getters'; import { checkForDuplicateTitle, OnSaveProps } from '../../../../src/plugins/saved_objects/public'; import { getCoreOverlays, getEmbeddableService, getSavedObjectsClient } from './kibana_services'; // @ts-expect-error @@ -67,7 +67,7 @@ export function getMapAttributeService(): MapAttributeService { copyOnSave: false, lastSavedTitle: '', getEsType: () => MAP_SAVED_OBJECT_TYPE, - getDisplayName: () => getMapEmbeddableDisplayName, + getDisplayName: getMapEmbeddableDisplayName, }, props.isTitleDuplicateConfirmed, props.onTitleDuplicate, diff --git a/x-pack/plugins/maps/public/render_app.tsx b/x-pack/plugins/maps/public/render_app.tsx index 29b1464af4ca5..17676503786f8 100644 --- a/x-pack/plugins/maps/public/render_app.tsx +++ b/x-pack/plugins/maps/public/render_app.tsx @@ -24,6 +24,7 @@ import { IKbnUrlStateStorage, } from '../../../../src/plugins/kibana_utils/public'; import { MapList, MapApp } from './routes'; +import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; export let goToSpecifiedPath: (path: string) => void; export let kbnUrlStateStorage: IKbnUrlStateStorage; @@ -84,10 +85,12 @@ export async function renderApp({ let mapEmbeddableInput; if (routeProps.match.params.savedMapId) { - mapEmbeddableInput = { savedObjectId: routeProps.match.params.savedMapId }; + mapEmbeddableInput = { + savedObjectId: routeProps.match.params.savedMapId, + } as MapByReferenceInput; } if (valueInput) { - mapEmbeddableInput = valueInput; + mapEmbeddableInput = valueInput as MapByValueInput; } return ( diff --git a/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx index 4e9902065f8b4..e0fae5125d1b3 100644 --- a/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx @@ -178,7 +178,7 @@ export class MapsListView extends React.Component { this.setState({ showDeleteModal: true }); }; - onTableChange = ({ page, sort }: CriteriaWithPagination) => { + onTableChange = ({ page, sort }: CriteriaWithPagination) => { const { index: pageIndex, size: pageSize } = page; let { field: sortField, direction: sortDirection } = sort || {}; @@ -401,7 +401,7 @@ export class MapsListView extends React.Component { let selection; if (!this.state.readOnly) { selection = { - onSelectionChange: (s: SelectionItem[]) => { + onSelectionChange: (s: TableRow[]) => { this.setState({ selectedIds: s.map((item) => { return item.id; diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx index 6addcbfbf326d..b9df1eefdb8bf 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx @@ -9,7 +9,7 @@ import 'mapbox-gl/dist/mapbox-gl.css'; import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { AppLeaveAction, AppMountParameters } from 'kibana/public'; -import { EmbeddableStateTransfer, Adapters } from 'src/plugins/embeddable/public'; +import { Adapters } from 'src/plugins/embeddable/public'; import { Subscription } from 'rxjs'; import { getData, @@ -39,13 +39,7 @@ import { import { MapContainer } from '../../connected_components/map_container'; import { getIndexPatternsFromIds } from '../../index_pattern_util'; import { getTopNavConfig } from './top_nav_config'; -import { - LayerDescriptor, - MapRefreshConfig, - MapCenterAndZoom, - MapQuery, -} from '../../../common/descriptor_types'; -import { MapSettings } from '../../reducers/map'; +import { MapRefreshConfig, MapQuery } from '../../../common/descriptor_types'; import { goToSpecifiedPath } from '../../render_app'; import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; import { getExistingMapPath } from '../../../common/constants'; @@ -62,7 +56,6 @@ import { interface Props { savedMap: SavedMap; onAppLeave: AppMountParameters['onAppLeave']; - layerListConfigOnly: LayerDescriptor[]; filters: Filter[]; isFullScreen: boolean; isOpenSettingsDisabled: boolean; @@ -332,12 +325,12 @@ export class MapApp extends React.Component { } this.props.savedMap.setBreadcrumbs(); - getCoreChrome().docTitle.change(mapSavedObjectAttributes.title); + getCoreChrome().docTitle.change(this.props.savedMap.getTitle()); const savedObjectId = this.props.savedMap.getSavedObjectId(); if (savedObjectId) { getCoreChrome().recentlyAccessed.add( getExistingMapPath(savedObjectId), - mapSavedObjectAttributes.title, + this.props.savedMap.getTitle(), savedObjectId ); } diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts index ba7535fda7bf8..49ea383bdfef0 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts +++ b/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts @@ -20,15 +20,9 @@ import { } from '../../selectors/map_selectors'; import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../actions'; import { FLYOUT_STATE } from '../../reducers/ui'; -import { getMapsCapabilities } from '../../kibana_services'; import { getInspectorAdapters } from '../../reducers/non_serializable_instances'; import { MapStoreState } from '../../reducers/store'; -import { - MapRefreshConfig, - MapCenterAndZoom, - LayerDescriptor, -} from '../../../common/descriptor_types'; -import { MapSettings } from '../../reducers/map'; +import { MapRefreshConfig } from '../../../common/descriptor_types'; function mapStateToProps(state: MapStoreState) { return { diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx index 1f0f7ba1a9e63..d32ecf83e0231 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx @@ -10,7 +10,7 @@ import { AppMountParameters } from 'kibana/public'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapApp } from './map_app_connector'; import { SavedMap } from './saved_map'; -import { MapEmbeddableInput } from '../../../embeddable/types'; +import { MapEmbeddableInput } from '../../embeddable/types'; interface Props { mapEmbeddableInput?: MapEmbeddableInput; @@ -21,11 +21,15 @@ interface Props { originatingApp?: string; } +interface State { + savedMap: SavedMap; +} + // react-router-dom.route "render" method may be called multiple times for the same route. // Therefore state can not exist in the "render" closure // MapAppContainer exists to wrap MapApp in a component so that a single instance of SavedMap // exists per route regardless of how many times render method is called. -export class MapAppContainer extends Component { +export class MapAppContainer extends Component { constructor(props: Props) { super(props); this.state = { @@ -45,7 +49,6 @@ export class MapAppContainer extends Component { savedMap={this.state.savedMap} onAppLeave={this.props.onAppLeave} setHeaderActionMenu={this.props.setHeaderActionMenu} - getAppNameFromId={this.props.stateTransfer.getAppNameFromId} /> ); diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index 1ba14ddc625c9..c7b159a622123 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; @@ -32,15 +33,10 @@ import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_sele import { getMapAttributeService } from '../../../map_attribute_service'; import { OnSaveProps } from '../../../../../../../src/plugins/saved_objects/public'; import { MapByReferenceInput, MapEmbeddableInput } from '../../../embeddable/types'; -import { - getCoreChrome, - getCoreOverlays, - getSavedObjectsClient, - getToasts, -} from '../../../kibana_services'; +import { getCoreChrome, getToasts } from '../../../kibana_services'; import { goToSpecifiedPath } from '../../../render_app'; -import { LayerDescriptor } from '../../../../common/descriptor_types'; -import { getInitialLayers, getInitialLayersFromUrlParam } from './get_initial_layers'; +import { LayerDescriptor, MapCenterAndZoom } from '../../../../common/descriptor_types'; +import { getInitialLayers } from './get_initial_layers'; import { copyPersistentState } from '../../../reducers/util'; import { getBreadcrumbs } from './get_breadcrumbs'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; @@ -146,7 +142,7 @@ export class SavedMap { this._attributes.layerListJSON, overrides && overrides.defaultLayers !== undefined ? overrides.defaultLayers : [] ); - this._store.dispatch(replaceLayerList(layerList)); + this._store.dispatch(replaceLayerList(layerList)); if (overrides && overrides.hiddenLayers !== undefined) { this._store.dispatch(setHiddenLayers(overrides.hiddenLayers)); } @@ -188,7 +184,7 @@ export class SavedMap { } const breadcrumbs = getBreadcrumbs({ - title: this._attributes.title, + title: this._attributes.title ? this._attributes.title : '', getHasUnsavedChanges: this.hasUnsavedChanges, originatingApp: this._originatingApp, getAppNameFromId: this._getStateTransfer().getAppNameFromId, @@ -197,7 +193,9 @@ export class SavedMap { } public getSavedObjectId(): string | undefined { - return this._mapEmbeddableInput?.savedObjectId; + return this._mapEmbeddableInput && 'savedObjectId' in this._mapEmbeddableInput + ? (this._mapEmbeddableInput as MapByReferenceInput).savedObjectId + : undefined; } public getOriginatingApp(): string | undefined { @@ -212,6 +210,13 @@ export class SavedMap { return !!this._originatingApp; } + public getTitle(): string { + if (!this._attributes) { + throw new Error('Invalid usage, must await getTitle before calling getAttributes'); + } + return this._attributes.title !== undefined ? this._attributes.title : ''; + } + public getAttributes(): MapSavedObjectAttributes { if (!this._attributes) { throw new Error('Invalid usage, must await loadAttributes before calling getAttributes'); @@ -242,11 +247,11 @@ export class SavedMap { let updatedMapEmbeddableInput: MapEmbeddableInput; try { - updatedMapEmbeddableInput = await getMapAttributeService().wrapAttributes( + updatedMapEmbeddableInput = (await getMapAttributeService().wrapAttributes( this._attributes, saveByReference, newCopyOnSave ? undefined : this._mapEmbeddableInput - ); + )) as MapEmbeddableInput; } catch (e) { // Error toast displayed by wrapAttributes this._attributes.title = prevTitle; @@ -257,11 +262,11 @@ export class SavedMap { if (returnToOrigin) { if (!this._originatingApp) { getToasts().addDanger({ - title: i18n.translate('xpack.maps.topNav.saveErrorMessage', { + title: i18n.translate('xpack.maps.topNav.saveErrorTitle', { defaultMessage: `Error saving '{title}'`, values: { title: newTitle }, }), - text: i18n.translate('xpack.maps.topNav.saveErrorMessage', { + text: i18n.translate('xpack.maps.topNav.saveErrorText', { defaultMessage: 'Unable to return to app without an originating app', }), }); diff --git a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx index faf9ef3a8ec05..bbb7adfbf10be 100644 --- a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx @@ -11,9 +11,7 @@ import { getCoreChrome, getMapsCapabilities, getInspector, - getToasts, getCoreI18n, - getNavigateToApp, getIsAllowByValueEmbeddables, getSavedObjectsClient, getCoreOverlays, @@ -25,9 +23,7 @@ import { showSaveModal, } from '../../../../../../src/plugins/saved_objects/public'; import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; -import { goToSpecifiedPath } from '../../render_app'; import { SavedMap } from './saved_map'; -import { EmbeddableStateTransfer } from '../../../../../../src/plugins/embeddable/public'; import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters'; function getSaveAndReturnButtonLabel() { @@ -47,7 +43,6 @@ export function getTopNavConfig({ enableFullScreen, openMapSettings, inspectorAdapters, - getAppNameFromId, }: { savedMap: SavedMap; isOpenSettingsDisabled: boolean; @@ -143,10 +138,7 @@ export function getTopNavConfig({ id: props.newCopyOnSave ? undefined : savedMap.getSavedObjectId(), title: props.newTitle, copyOnSave: props.newCopyOnSave, - lastSavedTitle: - savedMap.getSavedObjectId() && savedMap.getAttributes() - ? savedMap.getAttributes().title - : undefined, + lastSavedTitle: savedMap.getSavedObjectId() ? savedMap.getTitle() : '', getEsType: () => MAP_SAVED_OBJECT_TYPE, getDisplayName: getMapEmbeddableDisplayName, }, @@ -173,7 +165,7 @@ export function getTopNavConfig({ documentInfo={{ description: mapSavedObjectAttributes.description, id: savedMap.getSavedObjectId(), - title: mapSavedObjectAttributes.title, + title: savedMap.getTitle(), }} objectType={i18n.translate('xpack.maps.topNav.saveModalType', { defaultMessage: 'map', @@ -194,7 +186,7 @@ export function getTopNavConfig({ iconType: 'checkInCircleFilled', run: () => { savedMap.save({ - newTitle: mapSavedObjectAttributes.title ? mapSavedObjectAttributes.title : '', + newTitle: savedMap.getTitle(), newDescription: mapSavedObjectAttributes.description ? mapSavedObjectAttributes.description : '', diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts b/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts index fda19bed25be7..3072ab8280c41 100644 --- a/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts +++ b/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts @@ -10,5 +10,5 @@ export { startGlobalStateSyncing, MapsGlobalState, } from './global_sync'; -export { AppStateManager } from './app_state_manager'; +export { AppStateManager, MapsAppState } from './app_state_manager'; export { startAppStateSyncing } from './app_sync'; diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx index 4ac759ea534ec..67675a47666e4 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx @@ -68,6 +68,7 @@ export const createEmbeddable = async ( const input: MapEmbeddableInput = { title: i18n.MAP_TITLE, + attributes: {}, id: uuid.v4(), filters, hidePanelTitles: true, @@ -115,7 +116,7 @@ export const createEmbeddable = async ( if (!isErrorEmbeddable(embeddableObject)) { embeddableObject.setRenderTooltipContent(renderTooltipContent); // @ts-expect-error - await embeddableObject.setLayerList(getLayerList(indexPatterns)); + embeddableObject.setLayerList(getLayerList(indexPatterns)); } // Wire up to app refresh action diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index aa429e416e715..1cc8253f1096c 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11336,8 +11336,6 @@ "xpack.maps.layerWizardSelect.solutionsCategoryLabel": "ソリューション", "xpack.maps.loadMap.errorAttemptingToLoadSavedMap": "マップを読み込めません", "xpack.maps.map.initializeErrorTitle": "マップを初期化できません", - "xpack.maps.mapEmbeddableFactory.invalidLayerList": "不正な形式のレイヤーリストによりマップを読み込めません", - "xpack.maps.mapEmbeddableFactory.invalidSavedObject": "不正な形式の保存済みオブジェクトによりマップを読み込めません", "xpack.maps.mapListing.advancedSettingsLinkText": "高度な設定", "xpack.maps.mapListing.cancelTitle": "キャンセル", "xpack.maps.mapListing.createMapButtonLabel": "マップを作成", @@ -11655,7 +11653,6 @@ "xpack.maps.topNav.openSettingsDescription": "マップ設定を開く", "xpack.maps.topNav.saveAndReturnButtonLabel": "保存して戻る", "xpack.maps.topNav.saveAsButtonLabel": "名前を付けて保存", - "xpack.maps.topNav.saveErrorMessage": "「{title}」の保存エラー", "xpack.maps.topNav.saveMapButtonLabel": "保存", "xpack.maps.topNav.saveMapDescription": "マップを保存", "xpack.maps.topNav.saveMapDisabledButtonTooltip": "保存する前に、レイヤーの変更を保存するか、キャンセルしてください", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index e8957a96e460f..360b373cb48d7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -11349,8 +11349,6 @@ "xpack.maps.layerWizardSelect.solutionsCategoryLabel": "解决方案", "xpack.maps.loadMap.errorAttemptingToLoadSavedMap": "无法加载地图", "xpack.maps.map.initializeErrorTitle": "无法初始化地图", - "xpack.maps.mapEmbeddableFactory.invalidLayerList": "无法加载地图,图层列表格式不正确", - "xpack.maps.mapEmbeddableFactory.invalidSavedObject": "无法加载地图,已保存对象格式错误", "xpack.maps.mapListing.advancedSettingsLinkText": "高级设置", "xpack.maps.mapListing.cancelTitle": "取消", "xpack.maps.mapListing.createMapButtonLabel": "创建地图", @@ -11668,7 +11666,6 @@ "xpack.maps.topNav.openSettingsDescription": "打开地图设置", "xpack.maps.topNav.saveAndReturnButtonLabel": "保存并返回", "xpack.maps.topNav.saveAsButtonLabel": "另存为", - "xpack.maps.topNav.saveErrorMessage": "保存“{title}”时出错", "xpack.maps.topNav.saveMapButtonLabel": "保存", "xpack.maps.topNav.saveMapDescription": "保存地图", "xpack.maps.topNav.saveMapDisabledButtonTooltip": "保存前确认或取消您的图层更改", diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx index 85ac016333363..95c9760f5084c 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx @@ -66,6 +66,7 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp const input: MapEmbeddableInput = { id: uuid.v4(), + attributes: {}, filters: [], hidePanelTitles: true, refreshConfig: { @@ -127,7 +128,7 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp if (embeddableObject && !isErrorEmbeddable(embeddableObject)) { embeddableObject.setRenderTooltipContent(renderTooltipContent); - await embeddableObject.setLayerList(getLayerList(upPoints, downPoints, colors)); + embeddableObject.setLayerList(getLayerList(upPoints, downPoints, colors)); } setEmbeddable(embeddableObject); From 5d276670ead5a840b3678b8a8731e8512f7d184f Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 13:11:57 -0700 Subject: [PATCH 23/35] make title map saved object attribute required --- .../app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx | 2 +- .../canvas/canvas_plugin_src/functions/external/saved_map.ts | 2 +- .../renderers/embeddable/input_type_to_expression/map.test.ts | 2 +- x-pack/plugins/maps/common/map_saved_object_type.ts | 2 +- .../network/components/embeddables/embedded_map_helpers.tsx | 2 +- .../status_details/location_map/embeddables/embedded_map.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx index 6d476dd1aaa48..b757635af1702 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx @@ -77,7 +77,7 @@ export function EmbeddedMapComponent() { ); const input: MapEmbeddableInput = { - attributes: {}, + attributes: { title: '' }, id: uuid.v4(), filters: mapFilters, refreshConfig: { diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts index 67b31cbb1ffba..7bb6e43b38d59 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/external/saved_map.ts @@ -83,7 +83,7 @@ export function savedMap(): ExpressionFunctionDefinition< return { type: EmbeddableExpressionType, input: { - attributes: {}, + attributes: { title: '' }, id: args.id, filters: getQueryFilters(filters), timeRange: args.timerange || defaultTimeRange, diff --git a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts index acfe8d44f38a5..635e0ec2d0dcb 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/renderers/embeddable/input_type_to_expression/map.test.ts @@ -9,7 +9,7 @@ import { MapEmbeddableInput } from '../../../../../../plugins/maps/public/embedd import { fromExpression, Ast } from '@kbn/interpreter/common'; const baseSavedMapInput = { - attributes: {}, + attributes: { title: '' }, id: 'embeddableId', filters: [], isLayerTOCOpen: false, diff --git a/x-pack/plugins/maps/common/map_saved_object_type.ts b/x-pack/plugins/maps/common/map_saved_object_type.ts index e195d9e4538f0..ce9ffdc3b221d 100644 --- a/x-pack/plugins/maps/common/map_saved_object_type.ts +++ b/x-pack/plugins/maps/common/map_saved_object_type.ts @@ -8,7 +8,7 @@ import { SavedObject } from '../../../../src/core/types/saved_objects'; export type MapSavedObjectAttributes = { - title?: string; + title: string; description?: string; mapStateJSON?: string; layerListJSON?: string; diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx index 67675a47666e4..1d6ace3292a0d 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx @@ -68,7 +68,7 @@ export const createEmbeddable = async ( const input: MapEmbeddableInput = { title: i18n.MAP_TITLE, - attributes: {}, + attributes: { title: '' }, id: uuid.v4(), filters, hidePanelTitles: true, diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx index 95c9760f5084c..2da57ef3138c7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx @@ -66,7 +66,7 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp const input: MapEmbeddableInput = { id: uuid.v4(), - attributes: {}, + attributes: { title: '' }, filters: [], hidePanelTitles: true, refreshConfig: { From d5f5937a67e4d16ce23d9c89bffc9918d49791ab Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 14:17:36 -0700 Subject: [PATCH 24/35] fix jest tests --- x-pack/plugins/maps/public/actions/layer_actions.test.ts | 8 ++++++++ x-pack/plugins/maps/public/actions/map_actions.test.js | 7 +++++++ .../toolbar_overlay/toolbar_overlay.test.tsx | 8 ++++++++ .../layer_control/layer_toc/toc_entry/view.test.js | 8 ++++++++ .../plugins/maps/public/selectors/map_selectors.test.ts | 3 +++ 5 files changed, 34 insertions(+) diff --git a/x-pack/plugins/maps/public/actions/layer_actions.test.ts b/x-pack/plugins/maps/public/actions/layer_actions.test.ts index 09a22dca271d7..495243d62ca36 100644 --- a/x-pack/plugins/maps/public/actions/layer_actions.test.ts +++ b/x-pack/plugins/maps/public/actions/layer_actions.test.ts @@ -8,6 +8,14 @@ import { addLayer } from './layer_actions'; import { LayerDescriptor } from '../../common/descriptor_types'; import { LICENSED_FEATURES } from '../licensed_features'; +jest.mock('../kibana_services', () => { + return { + getMapsCapabilities() { + return { save: true }; + }, + }; +}); + const getStoreMock = jest.fn(); const dispatchMock = jest.fn(); diff --git a/x-pack/plugins/maps/public/actions/map_actions.test.js b/x-pack/plugins/maps/public/actions/map_actions.test.js index cbb6f0a4054cc..1d1f8a511c4fa 100644 --- a/x-pack/plugins/maps/public/actions/map_actions.test.js +++ b/x-pack/plugins/maps/public/actions/map_actions.test.js @@ -10,6 +10,13 @@ jest.mock('./data_request_actions', () => { syncDataForAllLayers: () => {}, }; }); +jest.mock('../kibana_services', () => { + return { + getMapsCapabilities() { + return { save: true }; + }, + }; +}); import { mapExtentChanged, setMouseCoordinates, setQuery } from './map_actions'; diff --git a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx index c03aa1e098540..6381285a8ef70 100644 --- a/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx +++ b/x-pack/plugins/maps/public/connected_components/toolbar_overlay/toolbar_overlay.test.tsx @@ -7,6 +7,14 @@ import React from 'react'; import { shallow } from 'enzyme'; +jest.mock('../../kibana_services', () => { + return { + getMapsCapabilities() { + return { save: true }; + }, + }; +}); + // @ts-ignore import { ToolbarOverlay } from './toolbar_overlay'; diff --git a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js index 543be9395d0bc..877e8658ab03e 100644 --- a/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js +++ b/x-pack/plugins/maps/public/connected_components/widget_overlay/layer_control/layer_toc/toc_entry/view.test.js @@ -7,6 +7,14 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +jest.mock('../../../../../kibana_services', () => { + return { + getMapsCapabilities() { + return { save: true }; + }, + }; +}); + import { TOCEntry } from './view'; const LAYER_ID = '1'; diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index 7f50ca9045038..eaac4ac3a17b7 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -24,6 +24,9 @@ jest.mock('../kibana_services', () => ({ }; }, }), + getMapsCapabilities() { + return { save: true }; + }, })); import { DEFAULT_MAP_STORE_STATE } from '../reducers/store'; From 3f5cedf67fae27f77b24e16ec0a492a8cc0a24fd Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 14:32:31 -0700 Subject: [PATCH 25/35] fix logic for hasSaveAndReturnConfig to not show save and return button with new map and allowByValueEmbeddables disabled --- .../maps/public/routes/map_app/saved_map/saved_map.ts | 6 ++++-- .../maps/public/routes/map_app/top_nav_config.tsx | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index c7b159a622123..d5dab1844538c 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -33,7 +33,7 @@ import { getIsLayerTOCOpen, getOpenTOCDetails } from '../../../selectors/ui_sele import { getMapAttributeService } from '../../../map_attribute_service'; import { OnSaveProps } from '../../../../../../../src/plugins/saved_objects/public'; import { MapByReferenceInput, MapEmbeddableInput } from '../../../embeddable/types'; -import { getCoreChrome, getToasts } from '../../../kibana_services'; +import { getCoreChrome, getToasts, getIsAllowByValueEmbeddables } from '../../../kibana_services'; import { goToSpecifiedPath } from '../../../render_app'; import { LayerDescriptor, MapCenterAndZoom } from '../../../../common/descriptor_types'; import { getInitialLayers } from './get_initial_layers'; @@ -207,7 +207,9 @@ export class SavedMap { }; public hasSaveAndReturnConfig() { - return !!this._originatingApp; + const hasOriginatingApp = !!this._originatingApp; + const isNewMap = !this.getSavedObjectId(); + return getIsAllowByValueEmbeddables() ? hasOriginatingApp : !isNewMap && hasOriginatingApp; } public getTitle(): string { diff --git a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx index bbb7adfbf10be..22a0be7bb2d27 100644 --- a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx @@ -101,7 +101,9 @@ export function getTopNavConfig({ if (getMapsCapabilities().save) { const hasSaveAndReturnConfig = savedMap.hasSaveAndReturnConfig(); - const mapSavedObjectAttributes = savedMap.getAttributes(); + const mapDescription = savedMap.getAttributes().description + ? savedMap.getAttributes().description + : ''; topNavConfigs.push({ id: 'save', @@ -163,7 +165,7 @@ export function getTopNavConfig({ }} onClose={() => {}} documentInfo={{ - description: mapSavedObjectAttributes.description, + description: mapDescription, id: savedMap.getSavedObjectId(), title: savedMap.getTitle(), }} @@ -187,9 +189,7 @@ export function getTopNavConfig({ run: () => { savedMap.save({ newTitle: savedMap.getTitle(), - newDescription: mapSavedObjectAttributes.description - ? mapSavedObjectAttributes.description - : '', + newDescription: mapDescription, newCopyOnSave: false, isTitleDuplicateConfirmed: false, returnToOrigin: true, From a631b95b40174b7fe82f32fc9c8ea042a0841575 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 4 Nov 2020 14:57:40 -0700 Subject: [PATCH 26/35] tslint --- x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx index 22a0be7bb2d27..2f2e4a687e6b4 100644 --- a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx @@ -102,7 +102,7 @@ export function getTopNavConfig({ if (getMapsCapabilities().save) { const hasSaveAndReturnConfig = savedMap.hasSaveAndReturnConfig(); const mapDescription = savedMap.getAttributes().description - ? savedMap.getAttributes().description + ? savedMap.getAttributes().description! : ''; topNavConfigs.push({ From 77522955a8d2b419dd73a1fda627a5e8de29b62a Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 5 Nov 2020 09:02:44 -0700 Subject: [PATCH 27/35] fix functional test by triggering MapApp render after save --- .../maps/public/routes/map_app/map_app.tsx | 2 ++ .../routes/map_app/map_app_container.tsx | 28 +++++++++++++++++-- .../routes/map_app/saved_map/saved_map.ts | 9 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx index b9df1eefdb8bf..a3d3709c51c59 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app.tsx @@ -55,6 +55,8 @@ import { interface Props { savedMap: SavedMap; + // saveCounter used to trigger MapApp render after SaveMap.save + saveCounter: number; onAppLeave: AppMountParameters['onAppLeave']; filters: Filter[]; isFullScreen: boolean; diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx index d32ecf83e0231..f6aea4438a45b 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx +++ b/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx @@ -23,6 +23,7 @@ interface Props { interface State { savedMap: SavedMap; + saveCounter: number; } // react-router-dom.route "render" method may be called multiple times for the same route. @@ -30,18 +31,38 @@ interface State { // MapAppContainer exists to wrap MapApp in a component so that a single instance of SavedMap // exists per route regardless of how many times render method is called. export class MapAppContainer extends Component { + private _isMounted: boolean = false; + constructor(props: Props) { super(props); this.state = { savedMap: new SavedMap({ mapEmbeddableInput: props.mapEmbeddableInput, - embeddableId: this.props.embeddableId, - originatingApp: this.props.originatingApp, - stateTransfer: this.props.stateTransfer, + embeddableId: props.embeddableId, + originatingApp: props.originatingApp, + stateTransfer: props.stateTransfer, + onSaveCallback: this.updateSaveCounter, }), + saveCounter: 0, }; } + componentDidMount() { + this._isMounted = true; + } + + componentWillUnmount() { + this._isMounted = false; + } + + updateSaveCounter = () => { + if (this._isMounted) { + this.setState((prevState) => { + return { saveCounter: prevState.saveCounter + 1 }; + }); + } + }; + render() { return ( @@ -49,6 +70,7 @@ export class MapAppContainer extends Component { savedMap={this.state.savedMap} onAppLeave={this.props.onAppLeave} setHeaderActionMenu={this.props.setHeaderActionMenu} + saveCounter={this.state.saveCounter} /> ); diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts index d5dab1844538c..39e56869c4c9a 100644 --- a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts @@ -46,6 +46,7 @@ export class SavedMap { private readonly _embeddableId?: string; private _initialLayerListConfig: LayerDescriptor[] = []; private _mapEmbeddableInput?: MapEmbeddableInput; + private readonly _onSaveCallback?: () => void; private _originatingApp?: string; private readonly _stateTransfer?: EmbeddableStateTransfer; private readonly _store: MapStore; @@ -53,16 +54,19 @@ export class SavedMap { constructor({ mapEmbeddableInput, embeddableId, + onSaveCallback, originatingApp, stateTransfer, }: { mapEmbeddableInput?: MapEmbeddableInput; embeddableId?: string; + onSaveCallback?: () => void; originatingApp?: string; stateTransfer?: EmbeddableStateTransfer; }) { this._mapEmbeddableInput = mapEmbeddableInput; this._embeddableId = embeddableId; + this._onSaveCallback = onSaveCallback; this._originatingApp = originatingApp; this._stateTransfer = stateTransfer; this._store = createMapStore(); @@ -297,6 +301,11 @@ export class SavedMap { getCoreChrome().docTitle.change(newTitle); this.setBreadcrumbs(); goToSpecifiedPath(`/map/${this.getSavedObjectId()}${window.location.hash}`); + + if (this._onSaveCallback) { + this._onSaveCallback(); + } + return; } From 5261de48df69dc30dbb8cb16920ca574818eda3d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 6 Nov 2020 15:17:49 -0700 Subject: [PATCH 28/35] rename map_app_container to map_page --- x-pack/plugins/maps/public/embeddable/map_embeddable.tsx | 2 +- x-pack/plugins/maps/public/render_app.tsx | 6 +++--- x-pack/plugins/maps/public/routes/index.ts | 4 ++-- .../plugins/maps/public/routes/{list => list_page}/index.ts | 2 +- .../routes/{list => list_page}/load_list_and_render.tsx | 0 .../public/routes/{list => list_page}/maps_list_view.tsx | 0 .../maps/public/routes/{map_app => map_page}/index.ts | 2 +- .../maps/public/routes/{map_app => map_page}/map_app.tsx | 0 .../routes/{map_app => map_page}/map_app_connector.ts | 0 .../map_app_container.tsx => map_page/map_page.tsx} | 2 +- .../saved_map/get_breadcrumbs.test.tsx | 0 .../{map_app => map_page}/saved_map/get_breadcrumbs.tsx | 0 .../saved_map/get_initial_layers.test.js | 0 .../{map_app => map_page}/saved_map/get_initial_layers.ts | 0 .../{map_app => map_page}/saved_map/get_initial_query.ts | 0 .../saved_map/get_initial_refresh_config.ts | 0 .../saved_map/get_initial_time_filters.ts | 0 .../public/routes/{map_app => map_page}/saved_map/index.ts | 0 .../routes/{map_app => map_page}/saved_map/saved_map.ts | 0 .../public/routes/{map_app => map_page}/top_nav_config.tsx | 0 .../{map_app => map_page}/url_state/app_state_manager.ts | 0 .../routes/{map_app => map_page}/url_state/app_sync.ts | 0 .../routes/{map_app => map_page}/url_state/global_sync.ts | 0 .../public/routes/{map_app => map_page}/url_state/index.ts | 0 24 files changed, 9 insertions(+), 9 deletions(-) rename x-pack/plugins/maps/public/routes/{list => list_page}/index.ts (77%) rename x-pack/plugins/maps/public/routes/{list => list_page}/load_list_and_render.tsx (100%) rename x-pack/plugins/maps/public/routes/{list => list_page}/maps_list_view.tsx (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/index.ts (81%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/map_app.tsx (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/map_app_connector.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app/map_app_container.tsx => map_page/map_page.tsx} (97%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_breadcrumbs.test.tsx (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_breadcrumbs.tsx (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_initial_layers.test.js (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_initial_layers.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_initial_query.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_initial_refresh_config.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/get_initial_time_filters.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/index.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/saved_map/saved_map.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/top_nav_config.tsx (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/url_state/app_state_manager.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/url_state/app_sync.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/url_state/global_sync.ts (100%) rename x-pack/plugins/maps/public/routes/{map_app => map_page}/url_state/index.ts (100%) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index 215f57f68db16..e5c792796d865 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -62,7 +62,7 @@ import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapContainer } from '../connected_components/map_container'; -import { SavedMap } from '../routes/map_app/saved_map'; +import { SavedMap } from '../routes/map_page'; import { getIndexPatternsFromIds } from '../index_pattern_util'; import { getMapAttributeService } from '../map_attribute_service'; diff --git a/x-pack/plugins/maps/public/render_app.tsx b/x-pack/plugins/maps/public/render_app.tsx index 17676503786f8..68b74211ee273 100644 --- a/x-pack/plugins/maps/public/render_app.tsx +++ b/x-pack/plugins/maps/public/render_app.tsx @@ -23,7 +23,7 @@ import { withNotifyOnErrors, IKbnUrlStateStorage, } from '../../../../src/plugins/kibana_utils/public'; -import { MapList, MapApp } from './routes'; +import { ListPage, MapPage } from './routes'; import { MapByValueInput, MapByReferenceInput } from './embeddable/types'; export let goToSpecifiedPath: (path: string) => void; @@ -94,7 +94,7 @@ export async function renderApp({ } return ( - ; } else if (pathname === '/' || pathname === '') { - return ; + return ; } else { return ; } diff --git a/x-pack/plugins/maps/public/routes/index.ts b/x-pack/plugins/maps/public/routes/index.ts index d790c8f226f1e..0244331c0730b 100644 --- a/x-pack/plugins/maps/public/routes/index.ts +++ b/x-pack/plugins/maps/public/routes/index.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export { MapApp, SavedMap } from './map_app'; -export { MapList } from './list'; +export { MapPage, SavedMap } from './map_page'; +export { ListPage } from './list_page'; diff --git a/x-pack/plugins/maps/public/routes/list/index.ts b/x-pack/plugins/maps/public/routes/list_page/index.ts similarity index 77% rename from x-pack/plugins/maps/public/routes/list/index.ts rename to x-pack/plugins/maps/public/routes/list_page/index.ts index abebdfd2cf8cd..0c278ff1f8225 100644 --- a/x-pack/plugins/maps/public/routes/list/index.ts +++ b/x-pack/plugins/maps/public/routes/list_page/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { LoadListAndRender as MapList } from './load_list_and_render'; +export { LoadListAndRender as ListPage } from './load_list_and_render'; diff --git a/x-pack/plugins/maps/public/routes/list/load_list_and_render.tsx b/x-pack/plugins/maps/public/routes/list_page/load_list_and_render.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/list/load_list_and_render.tsx rename to x-pack/plugins/maps/public/routes/list_page/load_list_and_render.tsx diff --git a/x-pack/plugins/maps/public/routes/list/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/list/maps_list_view.tsx rename to x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx diff --git a/x-pack/plugins/maps/public/routes/map_app/index.ts b/x-pack/plugins/maps/public/routes/map_page/index.ts similarity index 81% rename from x-pack/plugins/maps/public/routes/map_app/index.ts rename to x-pack/plugins/maps/public/routes/map_page/index.ts index 6afeb9f06fd01..f7bea5f2c6b7f 100644 --- a/x-pack/plugins/maps/public/routes/map_app/index.ts +++ b/x-pack/plugins/maps/public/routes/map_page/index.ts @@ -5,4 +5,4 @@ */ export { SavedMap } from './saved_map'; -export { MapAppContainer as MapApp } from './map_app_container'; +export { MapPage } from './map_page'; diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_page/map_app.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/map_app.tsx rename to x-pack/plugins/maps/public/routes/map_page/map_app.tsx diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts b/x-pack/plugins/maps/public/routes/map_page/map_app_connector.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/map_app_connector.ts rename to x-pack/plugins/maps/public/routes/map_page/map_app_connector.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx similarity index 97% rename from x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx rename to x-pack/plugins/maps/public/routes/map_page/map_page.tsx index f6aea4438a45b..dad14e777b627 100644 --- a/x-pack/plugins/maps/public/routes/map_app/map_app_container.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx @@ -30,7 +30,7 @@ interface State { // Therefore state can not exist in the "render" closure // MapAppContainer exists to wrap MapApp in a component so that a single instance of SavedMap // exists per route regardless of how many times render method is called. -export class MapAppContainer extends Component { +export class MapPage extends Component { private _isMounted: boolean = false; constructor(props: Props) { diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.test.tsx rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_breadcrumbs.tsx rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.test.js b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_layers.test.js similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.test.js rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_layers.test.js diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_layers.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_layers.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_layers.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_query.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_query.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_query.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_query.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_refresh_config.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_refresh_config.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_refresh_config.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_refresh_config.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_time_filters.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_time_filters.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/get_initial_time_filters.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/get_initial_time_filters.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/index.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/index.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/index.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/saved_map/saved_map.ts rename to x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/top_nav_config.tsx rename to x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/app_state_manager.ts b/x-pack/plugins/maps/public/routes/map_page/url_state/app_state_manager.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/url_state/app_state_manager.ts rename to x-pack/plugins/maps/public/routes/map_page/url_state/app_state_manager.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/app_sync.ts b/x-pack/plugins/maps/public/routes/map_page/url_state/app_sync.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/url_state/app_sync.ts rename to x-pack/plugins/maps/public/routes/map_page/url_state/app_sync.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/global_sync.ts b/x-pack/plugins/maps/public/routes/map_page/url_state/global_sync.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/url_state/global_sync.ts rename to x-pack/plugins/maps/public/routes/map_page/url_state/global_sync.ts diff --git a/x-pack/plugins/maps/public/routes/map_app/url_state/index.ts b/x-pack/plugins/maps/public/routes/map_page/url_state/index.ts similarity index 100% rename from x-pack/plugins/maps/public/routes/map_app/url_state/index.ts rename to x-pack/plugins/maps/public/routes/map_page/url_state/index.ts From c13676f80e0e234ed9e7ae94857d2a7c4fa1951b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 6 Nov 2020 15:35:58 -0700 Subject: [PATCH 29/35] move MapApp and redux connector into folder --- .../index.ts} | 14 ++++++------ .../routes/map_page/{ => map_app}/map_app.tsx | 22 +++++++++---------- .../maps/public/routes/map_page/map_page.tsx | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) rename x-pack/plugins/maps/public/routes/map_page/{map_app_connector.ts => map_app/index.ts} (82%) rename x-pack/plugins/maps/public/routes/map_page/{ => map_app}/map_app.tsx (94%) diff --git a/x-pack/plugins/maps/public/routes/map_page/map_app_connector.ts b/x-pack/plugins/maps/public/routes/map_page/map_app/index.ts similarity index 82% rename from x-pack/plugins/maps/public/routes/map_page/map_app_connector.ts rename to x-pack/plugins/maps/public/routes/map_page/map_app/index.ts index 49ea383bdfef0..5c5031bb6a24e 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_app_connector.ts +++ b/x-pack/plugins/maps/public/routes/map_page/map_app/index.ts @@ -9,7 +9,7 @@ import { ThunkDispatch } from 'redux-thunk'; import { AnyAction } from 'redux'; import { Filter, Query, TimeRange } from 'src/plugins/data/public'; import { MapApp } from './map_app'; -import { getFlyoutDisplay, getIsFullScreen } from '../../selectors/ui_selectors'; +import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors'; import { getFilters, getQuery, @@ -17,12 +17,12 @@ import { getRefreshConfig, getTimeFilters, hasDirtyState, -} from '../../selectors/map_selectors'; -import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../actions'; -import { FLYOUT_STATE } from '../../reducers/ui'; -import { getInspectorAdapters } from '../../reducers/non_serializable_instances'; -import { MapStoreState } from '../../reducers/store'; -import { MapRefreshConfig } from '../../../common/descriptor_types'; +} from '../../../selectors/map_selectors'; +import { setQuery, setRefreshConfig, enableFullScreen, openMapSettings } from '../../../actions'; +import { FLYOUT_STATE } from '../../../reducers/ui'; +import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; +import { MapStoreState } from '../../../reducers/store'; +import { MapRefreshConfig } from '../../../../common/descriptor_types'; function mapStateToProps(state: MapStoreState) { return { diff --git a/x-pack/plugins/maps/public/routes/map_page/map_app.tsx b/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx similarity index 94% rename from x-pack/plugins/maps/public/routes/map_page/map_app.tsx rename to x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx index a3d3709c51c59..813af60c3cf2d 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx @@ -17,7 +17,7 @@ import { getMapsCapabilities, getNavigation, getToasts, -} from '../../kibana_services'; +} from '../../../kibana_services'; import { AppStateManager, startAppStateSyncing, @@ -25,7 +25,7 @@ import { updateGlobalState, startGlobalStateSyncing, MapsGlobalState, -} from './url_state'; +} from '../url_state'; import { esFilters, Filter, @@ -35,14 +35,14 @@ import { SavedQuery, QueryStateChange, QueryState, -} from '../../../../../../src/plugins/data/public'; -import { MapContainer } from '../../connected_components/map_container'; -import { getIndexPatternsFromIds } from '../../index_pattern_util'; -import { getTopNavConfig } from './top_nav_config'; -import { MapRefreshConfig, MapQuery } from '../../../common/descriptor_types'; -import { goToSpecifiedPath } from '../../render_app'; -import { MapSavedObjectAttributes } from '../../../common/map_saved_object_type'; -import { getExistingMapPath } from '../../../common/constants'; +} from '../../../../../../../src/plugins/data/public'; +import { MapContainer } from '../../../connected_components/map_container'; +import { getIndexPatternsFromIds } from '../../../index_pattern_util'; +import { getTopNavConfig } from '../top_nav_config'; +import { MapRefreshConfig, MapQuery } from '../../../../common/descriptor_types'; +import { goToSpecifiedPath } from '../../../render_app'; +import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; +import { getExistingMapPath } from '../../../../common/constants'; import { getInitialLayersFromUrlParam, getInitialQuery, @@ -51,7 +51,7 @@ import { SavedMap, unsavedChangesTitle, unsavedChangesWarning, -} from './saved_map'; +} from '../saved_map'; interface Props { savedMap: SavedMap; diff --git a/x-pack/plugins/maps/public/routes/map_page/map_page.tsx b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx index dad14e777b627..78809f66a346b 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_page.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx @@ -8,7 +8,7 @@ import React, { Component } from 'react'; import { Provider } from 'react-redux'; import { AppMountParameters } from 'kibana/public'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; -import { MapApp } from './map_app_connector'; +import { MapApp } from './map_app'; import { SavedMap } from './saved_map'; import { MapEmbeddableInput } from '../../embeddable/types'; From 58b44320c443dd9341afbccca2c914378161a83b Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 6 Nov 2020 15:49:40 -0700 Subject: [PATCH 30/35] review feedback --- .../maps/public/embeddable/map_embeddable.tsx | 26 ++++------ .../routes/map_page/map_app/map_app.tsx | 11 ++--- .../maps/public/routes/map_page/map_page.tsx | 3 +- .../routes/map_page/saved_map/saved_map.ts | 47 ++++++++----------- 4 files changed, 35 insertions(+), 52 deletions(-) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index e5c792796d865..fde69ad86c4fd 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -103,27 +103,21 @@ export class MapEmbeddable ); this._savedMap = new SavedMap({ mapEmbeddableInput: initialInput }); - this.initializeSaveMap(); + this._initializeSaveMap(); this._subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input)); } - private async initializeSaveMap() { - const overrides = { - isLayerTOCOpen: this.input.isLayerTOCOpen, - openTOCDetails: this.input.openTOCDetails, - mapCenter: this.input.mapCenter, - hiddenLayers: this.input.hiddenLayers, - }; - await this._savedMap.loadAttributes(overrides); - this.initializeStore(); - this.initializeOutput(); + private async _initializeSaveMap() { + await this._savedMap.whenReady(); + this._initializeStore(); + this._initializeOutput(); this._isInitialized = true; if (this._domNode) { this.render(this._domNode); } } - private async initializeStore() { + private async _initializeStore() { const store = this._savedMap.getStore(); store.dispatch(setReadOnly(true)); store.dispatch(disableScrollZoom()); @@ -162,7 +156,7 @@ export class MapEmbeddable }); } - private async initializeOutput() { + private async _initializeOutput() { const savedMapTitle = this._savedMap.getAttributes()?.title ? this._savedMap.getAttributes().title : ''; @@ -175,7 +169,7 @@ export class MapEmbeddable title, editPath: `/${MAP_PATH}/${savedObjectId}`, editUrl: getHttp().basePath.prepend(getExistingMapPath(savedObjectId)), - indexPatterns: await this.getIndexPatterns(), + indexPatterns: await this._getIndexPatterns(), }); } @@ -306,7 +300,7 @@ export class MapEmbeddable setLayerList(layerList: LayerDescriptor[]) { this._savedMap.getStore().dispatch(replaceLayerList(layerList)); - this.getIndexPatterns().then((indexPatterns) => { + this._getIndexPatterns().then((indexPatterns) => { this.updateOutput({ ...this.getOutput(), indexPatterns, @@ -314,7 +308,7 @@ export class MapEmbeddable }); } - private async getIndexPatterns() { + private async _getIndexPatterns() { const queryableIndexPatternIds = getQueryableUniqueIndexPatternIds( this._savedMap.getStore().getState() ); diff --git a/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx b/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx index 813af60c3cf2d..817fbf3656103 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/map_app/map_app.tsx @@ -44,7 +44,6 @@ import { goToSpecifiedPath } from '../../../render_app'; import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; import { getExistingMapPath } from '../../../../common/constants'; import { - getInitialLayersFromUrlParam, getInitialQuery, getInitialRefreshConfig, getInitialTimeFilters, @@ -303,12 +302,8 @@ export class MapApp extends React.Component { }; async _initMap() { - let mapSavedObjectAttributes; try { - const overrides = { - defaultLayers: getInitialLayersFromUrlParam(), - }; - mapSavedObjectAttributes = await this.props.savedMap.loadAttributes(overrides); + await this.props.savedMap.whenReady(); } catch (err) { if (this._isMounted) { getToasts().addWarning({ @@ -322,7 +317,7 @@ export class MapApp extends React.Component { return; } - if (!this._isMounted || !mapSavedObjectAttributes) { + if (!this._isMounted) { return; } @@ -337,7 +332,7 @@ export class MapApp extends React.Component { ); } - this._initMapAndLayerSettings(mapSavedObjectAttributes); + this._initMapAndLayerSettings(this.props.savedMap.getAttributes()); this.setState({ initialized: true }); } diff --git a/x-pack/plugins/maps/public/routes/map_page/map_page.tsx b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx index 78809f66a346b..c8c9f620845ee 100644 --- a/x-pack/plugins/maps/public/routes/map_page/map_page.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/map_page.tsx @@ -9,7 +9,7 @@ import { Provider } from 'react-redux'; import { AppMountParameters } from 'kibana/public'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapApp } from './map_app'; -import { SavedMap } from './saved_map'; +import { SavedMap, getInitialLayersFromUrlParam } from './saved_map'; import { MapEmbeddableInput } from '../../embeddable/types'; interface Props { @@ -37,6 +37,7 @@ export class MapPage extends Component { super(props); this.state = { savedMap: new SavedMap({ + defaultLayers: getInitialLayersFromUrlParam(), mapEmbeddableInput: props.mapEmbeddableInput, embeddableId: props.embeddableId, originatingApp: props.originatingApp, diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 39e56869c4c9a..75aa8b419d401 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -43,6 +43,7 @@ import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; export class SavedMap { private _attributes: MapSavedObjectAttributes | null = null; + private readonly _defaultLayers: LayerDescriptor[]; private readonly _embeddableId?: string; private _initialLayerListConfig: LayerDescriptor[] = []; private _mapEmbeddableInput?: MapEmbeddableInput; @@ -52,18 +53,21 @@ export class SavedMap { private readonly _store: MapStore; constructor({ + defaultLayers = [], mapEmbeddableInput, embeddableId, onSaveCallback, originatingApp, stateTransfer, }: { + defaultLayers: LayerDescriptor[]; mapEmbeddableInput?: MapEmbeddableInput; embeddableId?: string; onSaveCallback?: () => void; originatingApp?: string; stateTransfer?: EmbeddableStateTransfer; }) { + this._defaultLayers = defaultLayers; this._mapEmbeddableInput = mapEmbeddableInput; this._embeddableId = embeddableId; this._onSaveCallback = onSaveCallback; @@ -76,13 +80,7 @@ export class SavedMap { return this._store; } - async loadAttributes(overrides?: { - isLayerTOCOpen?: boolean; - openTOCDetails?: string[]; - mapCenter?: MapCenterAndZoom; - hiddenLayers?: string[]; - defaultLayers?: LayerDescriptor[]; - }) { + async whenReady() { if (!this._mapEmbeddableInput) { this._attributes = { title: i18n.translate('xpack.maps.newMapTitle', { @@ -102,8 +100,8 @@ export class SavedMap { } let isLayerTOCOpen = DEFAULT_IS_LAYER_TOC_OPEN; - if (overrides && overrides.isLayerTOCOpen !== undefined) { - isLayerTOCOpen = overrides.isLayerTOCOpen; + if (this._mapEmbeddableInput && this._mapEmbeddableInput.isLayerTOCOpen !== undefined) { + isLayerTOCOpen = this._mapEmbeddableInput.isLayerTOCOpen; } else if (this._attributes?.uiStateJSON) { const uiState = JSON.parse(this._attributes.uiStateJSON); if ('isLayerTOCOpen' in uiState) { @@ -113,8 +111,8 @@ export class SavedMap { this._store.dispatch(setIsLayerTOCOpen(isLayerTOCOpen)); let openTOCDetails = []; - if (overrides && overrides.openTOCDetails !== undefined) { - openTOCDetails = overrides.openTOCDetails; + if (this._mapEmbeddableInput && this._mapEmbeddableInput.openTOCDetails !== undefined) { + openTOCDetails = this._mapEmbeddableInput.openTOCDetails; } else if (this._attributes?.uiStateJSON) { const uiState = JSON.parse(this._attributes.uiStateJSON); if ('openTOCDetails' in uiState) { @@ -123,12 +121,12 @@ export class SavedMap { } this._store.dispatch(setOpenTOCDetails(openTOCDetails)); - if (overrides && overrides.mapCenter !== undefined) { + if (this._mapEmbeddableInput && this._mapEmbeddableInput.mapCenter !== undefined) { this._store.dispatch( setGotoWithCenter({ - lat: overrides.mapCenter.lat, - lon: overrides.mapCenter.lon, - zoom: overrides.mapCenter.zoom, + lat: this._mapEmbeddableInput.mapCenter.lat, + lon: this._mapEmbeddableInput.mapCenter.lon, + zoom: this._mapEmbeddableInput.mapCenter.zoom, }) ); } else if (this._attributes?.mapStateJSON) { @@ -142,22 +140,17 @@ export class SavedMap { ); } - const layerList = getInitialLayers( - this._attributes.layerListJSON, - overrides && overrides.defaultLayers !== undefined ? overrides.defaultLayers : [] - ); + const layerList = getInitialLayers(this._attributes.layerListJSON, this._defaultLayers); this._store.dispatch(replaceLayerList(layerList)); - if (overrides && overrides.hiddenLayers !== undefined) { - this._store.dispatch(setHiddenLayers(overrides.hiddenLayers)); + if (this._mapEmbeddableInput && this._mapEmbeddableInput.hiddenLayers !== undefined) { + this._store.dispatch(setHiddenLayers(this._mapEmbeddableInput.hiddenLayers)); } this._initialLayerListConfig = copyPersistentState(layerList); - - return this._attributes; } hasUnsavedChanges = () => { if (!this._attributes) { - throw new Error('Invalid usage, must await loadAttributes before calling hasUnsavedChanges'); + throw new Error('Invalid usage, must await whenReady before calling hasUnsavedChanges'); } const savedLayerList = this._attributes.layerListJSON @@ -184,7 +177,7 @@ export class SavedMap { setBreadcrumbs() { if (!this._attributes) { - throw new Error('Invalid usage, must await loadAttributes before calling hasUnsavedChanges'); + throw new Error('Invalid usage, must await whenReady before calling hasUnsavedChanges'); } const breadcrumbs = getBreadcrumbs({ @@ -225,7 +218,7 @@ export class SavedMap { public getAttributes(): MapSavedObjectAttributes { if (!this._attributes) { - throw new Error('Invalid usage, must await loadAttributes before calling getAttributes'); + throw new Error('Invalid usage, must await whenReady before calling getAttributes'); } return this._attributes; @@ -242,7 +235,7 @@ export class SavedMap { saveByReference: boolean; }) { if (!this._attributes) { - throw new Error('Invalid usage, must await loadAttributes before calling save'); + throw new Error('Invalid usage, must await whenReady before calling save'); } const prevTitle = this._attributes.title; From ace3e697e4bbe8d025905b96a26db99db2a29508 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 6 Nov 2020 15:54:43 -0700 Subject: [PATCH 31/35] use MAP_PATH constant --- .../maps/public/routes/list_page/maps_list_view.tsx | 2 +- .../maps/public/routes/map_page/saved_map/saved_map.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx index e0fae5125d1b3..97ed3d428d341 100644 --- a/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx +++ b/x-pack/plugins/maps/public/routes/list_page/maps_list_view.tsx @@ -374,7 +374,7 @@ export class MapsListView extends React.Component { { e.preventDefault(); - goToSpecifiedPath(`/map/${record.id}`); + goToSpecifiedPath(`/${MAP_PATH}/${record.id}`); }} data-test-subj={`mapListingTitleLink-${record.title.split(' ').join('-')}`} > diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 75aa8b419d401..4079f7a6afd56 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -8,7 +8,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; import { MapSavedObjectAttributes } from '../../../../common/map_saved_object_type'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; +import { MAP_PATH, MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; import { createMapStore, MapStore, MapStoreState } from '../../../reducers/store'; import { getTimeFilters, @@ -35,7 +35,7 @@ import { OnSaveProps } from '../../../../../../../src/plugins/saved_objects/publ import { MapByReferenceInput, MapEmbeddableInput } from '../../../embeddable/types'; import { getCoreChrome, getToasts, getIsAllowByValueEmbeddables } from '../../../kibana_services'; import { goToSpecifiedPath } from '../../../render_app'; -import { LayerDescriptor, MapCenterAndZoom } from '../../../../common/descriptor_types'; +import { LayerDescriptor } from '../../../../common/descriptor_types'; import { getInitialLayers } from './get_initial_layers'; import { copyPersistentState } from '../../../reducers/util'; import { getBreadcrumbs } from './get_breadcrumbs'; @@ -60,7 +60,7 @@ export class SavedMap { originatingApp, stateTransfer, }: { - defaultLayers: LayerDescriptor[]; + defaultLayers?: LayerDescriptor[]; mapEmbeddableInput?: MapEmbeddableInput; embeddableId?: string; onSaveCallback?: () => void; @@ -293,7 +293,7 @@ export class SavedMap { getCoreChrome().docTitle.change(newTitle); this.setBreadcrumbs(); - goToSpecifiedPath(`/map/${this.getSavedObjectId()}${window.location.hash}`); + goToSpecifiedPath(`/${MAP_PATH}/${this.getSavedObjectId()}${window.location.hash}`); if (this._onSaveCallback) { this._onSaveCallback(); From bd83e0a36327dc71c9bc00e57d3017e043d94f1c Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 9 Nov 2020 07:58:24 -0700 Subject: [PATCH 32/35] update by reference saved object on save and return --- .../maps/public/routes/map_page/saved_map/saved_map.ts | 6 ++++++ .../plugins/maps/public/routes/map_page/top_nav_config.tsx | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 4079f7a6afd56..1b7393ac22cf8 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -224,6 +224,12 @@ export class SavedMap { return this._attributes; } + public isByReference(): boolean { + return ( + this._mapEmbeddableInput && getMapAttributeService().inputIsRefType(this._mapEmbeddableInput) + ); + } + public async save({ newDescription, newTitle, diff --git a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx index 2f2e4a687e6b4..c9e741d76c8cd 100644 --- a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx @@ -194,7 +194,7 @@ export function getTopNavConfig({ isTitleDuplicateConfirmed: false, returnToOrigin: true, onTitleDuplicate: () => {}, - saveByReference: false, + saveByReference: savedMap.isByReference(), }); }, testId: 'mapSaveAndReturnButton', From 7921138b0366580da143c9396aa20e27278b24e1 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 9 Nov 2020 09:31:03 -0700 Subject: [PATCH 33/35] cleanup breadcrumbs and title --- .../saved_map/get_breadcrumbs.test.tsx | 27 ++++++++++++++++--- .../map_page/saved_map/get_breadcrumbs.tsx | 13 ++++++--- .../routes/map_page/saved_map/saved_map.ts | 26 +++++++++++++++--- .../public/routes/map_page/top_nav_config.tsx | 20 ++++++-------- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 6 files changed, 63 insertions(+), 25 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx index 7064663445fae..64726cff942a3 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.test.tsx @@ -14,15 +14,20 @@ const getHasUnsavedChanges = () => { }; test('should get breadcrumbs "Maps / mymap"', () => { - const breadcrumbs = getBreadcrumbs({ title: 'mymap', getHasUnsavedChanges }); + const breadcrumbs = getBreadcrumbs({ + pageTitle: 'mymap', + getHasUnsavedChanges, + isByValue: false, + }); expect(breadcrumbs.length).toBe(2); expect(breadcrumbs[0].text).toBe('Maps'); expect(breadcrumbs[1].text).toBe('mymap'); }); -test('should get breadcrumbs "Dashboard / mymap" with originatingApp', () => { +test('should get breadcrumbs "Dashboard / mymap" with originatingApp and by value', () => { const breadcrumbs = getBreadcrumbs({ - title: 'mymap', + pageTitle: 'mymap', + isByValue: true, getHasUnsavedChanges, originatingApp: 'dashboardId', getAppNameFromId: (appId) => { @@ -33,3 +38,19 @@ test('should get breadcrumbs "Dashboard / mymap" with originatingApp', () => { expect(breadcrumbs[0].text).toBe('Dashboard'); expect(breadcrumbs[1].text).toBe('mymap'); }); + +test('should get breadcrumbs "Dashboard / Maps / mymap" with originatingApp and not by value', () => { + const breadcrumbs = getBreadcrumbs({ + pageTitle: 'mymap', + isByValue: false, + getHasUnsavedChanges, + originatingApp: 'dashboardId', + getAppNameFromId: (appId) => { + return 'Dashboard'; + }, + }); + expect(breadcrumbs.length).toBe(3); + expect(breadcrumbs[0].text).toBe('Dashboard'); + expect(breadcrumbs[1].text).toBe('Maps'); + expect(breadcrumbs[2].text).toBe('mymap'); +}); diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx index 30eac5c1b4546..7f3d82c6eaab3 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/get_breadcrumbs.tsx @@ -21,17 +21,20 @@ export const unsavedChangesTitle = i18n.translate('xpack.maps.breadCrumbs.unsave }); export function getBreadcrumbs({ - title, + pageTitle, + isByValue, getHasUnsavedChanges, originatingApp, getAppNameFromId, }: { - title: string; + pageTitle: string; + isByValue: boolean; getHasUnsavedChanges: () => boolean; originatingApp?: string; getAppNameFromId?: (id: string) => string | undefined; }) { const breadcrumbs = []; + if (originatingApp && getAppNameFromId) { breadcrumbs.push({ onClick: () => { @@ -39,7 +42,9 @@ export function getBreadcrumbs({ }, text: getAppNameFromId(originatingApp), }); - } else { + } + + if (!isByValue) { breadcrumbs.push({ text: getAppTitle(), onClick: async () => { @@ -58,7 +63,7 @@ export function getBreadcrumbs({ }); } - breadcrumbs.push({ text: title }); + breadcrumbs.push({ text: pageTitle }); return breadcrumbs; } diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 1b7393ac22cf8..557a999dceed8 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -83,9 +83,7 @@ export class SavedMap { async whenReady() { if (!this._mapEmbeddableInput) { this._attributes = { - title: i18n.translate('xpack.maps.newMapTitle', { - defaultMessage: 'New map', - }), + title: '', description: '', }; } else { @@ -175,13 +173,28 @@ export class SavedMap { return this._stateTransfer; } + private _getPageTitle(): string { + if (!this._mapEmbeddableInput) { + return i18n.translate('xpack.maps.breadcrumbsCreate', { + defaultMessage: 'Create', + }); + } + + return this.isByValue() + ? i18n.translate('xpack.maps.breadcrumbsEditByValue', { + defaultMessage: 'Edit map', + }) + : this._attributes.title; + } + setBreadcrumbs() { if (!this._attributes) { throw new Error('Invalid usage, must await whenReady before calling hasUnsavedChanges'); } const breadcrumbs = getBreadcrumbs({ - title: this._attributes.title ? this._attributes.title : '', + pageTitle: this._getPageTitle(), + isByValue: this.isByValue(), getHasUnsavedChanges: this.hasUnsavedChanges, originatingApp: this._originatingApp, getAppNameFromId: this._getStateTransfer().getAppNameFromId, @@ -230,6 +243,11 @@ export class SavedMap { ); } + public isByValue(): boolean { + const hasSavedObjectId = !!this.getSavedObjectId(); + return getIsAllowByValueEmbeddables() && this._originatingApp && !hasSavedObjectId; + } + public async save({ newDescription, newTitle, diff --git a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx index c9e741d76c8cd..e58a7a837ba9d 100644 --- a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx @@ -12,7 +12,6 @@ import { getMapsCapabilities, getInspector, getCoreI18n, - getIsAllowByValueEmbeddables, getSavedObjectsClient, getCoreOverlays, } from '../../kibana_services'; @@ -26,16 +25,6 @@ import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants'; import { SavedMap } from './saved_map'; import { getMapEmbeddableDisplayName } from '../../../common/i18n_getters'; -function getSaveAndReturnButtonLabel() { - return getIsAllowByValueEmbeddables() - ? i18n.translate('xpack.maps.topNav.saveToMaps', { - defaultMessage: 'Save to maps', - }) - : i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { - defaultMessage: 'Save as', - }); -} - export function getTopNavConfig({ savedMap, isOpenSettingsDisabled, @@ -104,12 +93,19 @@ export function getTopNavConfig({ const mapDescription = savedMap.getAttributes().description ? savedMap.getAttributes().description! : ''; + const saveAndReturnButtonLabel = savedMap.isByValue() + ? i18n.translate('xpack.maps.topNav.saveToMapsButtonLabel', { + defaultMessage: 'Save to maps', + }) + : i18n.translate('xpack.maps.topNav.saveAsButtonLabel', { + defaultMessage: 'Save as', + }); topNavConfigs.push({ id: 'save', iconType: hasSaveAndReturnConfig ? undefined : 'save', label: hasSaveAndReturnConfig - ? getSaveAndReturnButtonLabel() + ? saveAndReturnButtonLabel : i18n.translate('xpack.maps.topNav.saveMapButtonLabel', { defaultMessage: `save`, }), diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4a1d684edf562..7a48da2d4bcaf 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11362,7 +11362,6 @@ "xpack.maps.mvtSource.tooltipsTitle": "ツールチップフィールド", "xpack.maps.mvtSource.trashButtonAriaLabel": "フィールドの削除", "xpack.maps.mvtSource.trashButtonTitle": "フィールドの削除", - "xpack.maps.newMapTitle": "新しいマップ", "xpack.maps.noIndexPattern.doThisLinkTextDescription": "インデックスパターンを作成します", "xpack.maps.noIndexPattern.doThisPrefixDescription": "次のことが必要です ", "xpack.maps.noIndexPattern.doThisSuffixDescription": " 地理空間フィールドを含む", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index bc9fe5e75ee6d..794f6a6e848b7 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -11375,7 +11375,6 @@ "xpack.maps.mvtSource.tooltipsTitle": "工具提示字段", "xpack.maps.mvtSource.trashButtonAriaLabel": "移除字段", "xpack.maps.mvtSource.trashButtonTitle": "移除字段", - "xpack.maps.newMapTitle": "新地图", "xpack.maps.noIndexPattern.doThisLinkTextDescription": "创建索引模式", "xpack.maps.noIndexPattern.doThisPrefixDescription": "您将需要 ", "xpack.maps.noIndexPattern.doThisSuffixDescription": " 使用地理空间字段。", From 8c11c29d1046e26ea5380c1783f77e1be311513f Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 9 Nov 2020 10:01:09 -0700 Subject: [PATCH 34/35] properly handle deleted map saved objects --- x-pack/plugins/maps/public/embeddable/map_embeddable.tsx | 7 ++++++- x-pack/plugins/maps/public/map_attribute_service.ts | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index fde69ad86c4fd..caf21431145d5 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -108,7 +108,12 @@ export class MapEmbeddable } private async _initializeSaveMap() { - await this._savedMap.whenReady(); + try { + await this._savedMap.whenReady(); + } catch (e) { + this.onFatalError(e); + return; + } this._initializeStore(); this._initializeOutput(); this._isInitialized = true; diff --git a/x-pack/plugins/maps/public/map_attribute_service.ts b/x-pack/plugins/maps/public/map_attribute_service.ts index 2bb5e07e4ad07..0e3ef1b9ea518 100644 --- a/x-pack/plugins/maps/public/map_attribute_service.ts +++ b/x-pack/plugins/maps/public/map_attribute_service.ts @@ -57,6 +57,10 @@ export function getMapAttributeService(): MapAttributeService { savedObjectId ); + if (savedObject.error) { + throw savedObject.error; + } + const { attributes } = injectReferences(savedObject); return attributes; }, From a5f4853d77d5259271306eac94efcfa5f482ffac Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 9 Nov 2020 10:09:31 -0700 Subject: [PATCH 35/35] tslint cleanup --- .../maps/public/routes/map_page/saved_map/saved_map.ts | 10 ++-------- .../maps/public/routes/map_page/top_nav_config.tsx | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts index 557a999dceed8..036f8cf11d374 100644 --- a/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts +++ b/x-pack/plugins/maps/public/routes/map_page/saved_map/saved_map.ts @@ -184,7 +184,7 @@ export class SavedMap { ? i18n.translate('xpack.maps.breadcrumbsEditByValue', { defaultMessage: 'Edit map', }) - : this._attributes.title; + : this._attributes!.title; } setBreadcrumbs() { @@ -237,15 +237,9 @@ export class SavedMap { return this._attributes; } - public isByReference(): boolean { - return ( - this._mapEmbeddableInput && getMapAttributeService().inputIsRefType(this._mapEmbeddableInput) - ); - } - public isByValue(): boolean { const hasSavedObjectId = !!this.getSavedObjectId(); - return getIsAllowByValueEmbeddables() && this._originatingApp && !hasSavedObjectId; + return getIsAllowByValueEmbeddables() && !!this._originatingApp && !hasSavedObjectId; } public async save({ diff --git a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx index e58a7a837ba9d..2d0a7d967a6cf 100644 --- a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx @@ -190,7 +190,7 @@ export function getTopNavConfig({ isTitleDuplicateConfirmed: false, returnToOrigin: true, onTitleDuplicate: () => {}, - saveByReference: savedMap.isByReference(), + saveByReference: !savedMap.isByValue(), }); }, testId: 'mapSaveAndReturnButton',