Skip to content

Commit

Permalink
[maps embeddable] fix map layers disappear from map panel when using …
Browse files Browse the repository at this point in the history
…session storage to continue editing a dashboard (#193629)

Closes #190468 and
#193601

Dashboard unsaved changes for a panel are obtained from the embeddable
comparator subject for each comparator. If comparator subject does not
return a value, then this information is lost when returning to a
dashboard with unsaved changes. This is why layers and filters where
disappearing from a map when returning to a dashboard with unsaved
changes. This PR resolves this issue by providing comparator subjects
and setters for `savedObjectId`, `attributes`, and `mapSettings`.

PR also resolves issue of passing props from `MapRenderer` component
into map embeddable. Instead of passing props via state, props should be
passed from `MapRenderer` parent api.

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
nreese and elasticmachine authored Sep 23, 2024
1 parent f6c5dd9 commit a8ebc7f
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 45 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/api/start_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { LayerDescriptor } from '../../common/descriptor_types';
import type { CreateLayerDescriptorParams } from '../classes/sources/es_search_source';
import type { SampleValuesConfig, EMSTermJoinConfig } from '../ems_autosuggest';
import type { Props as PassiveMapProps } from '../lens/passive_map';
import type { Props as MapProps } from '../react_embeddable/map_renderer';
import type { Props as MapProps } from '../react_embeddable/map_renderer/map_renderer';

export interface MapsStartApi {
createLayerDescriptors: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { first } from 'rxjs';
import type { Filter } from '@kbn/es-query';
import type { Query, TimeRange } from '@kbn/es-query';
import { RegionMapVisConfig } from './types';
import { MapRenderer } from '../../react_embeddable/map_renderer';
import { MapRenderer } from '../../react_embeddable/map_renderer/map_renderer';
import { createRegionMapLayerDescriptor } from '../../classes/layers/create_region_map_layer_descriptor';

interface Props {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { first } from 'rxjs';
import type { Filter } from '@kbn/es-query';
import type { Query, TimeRange } from '@kbn/es-query';
import type { TileMapVisConfig } from './types';
import { MapRenderer } from '../../react_embeddable/map_renderer';
import { MapRenderer } from '../../react_embeddable/map_renderer/map_renderer';
import { createTileMapLayerDescriptor } from '../../classes/layers/create_tile_map_layer_descriptor';

interface Props {
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/lens/passive_map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export function PassiveMap(props: Props) {
<ReactEmbeddableRenderer<MapSerializedState, MapRuntimeState, MapApi>
type={MAP_SAVED_OBJECT_TYPE}
getParentApi={() => ({
hideFilterActions: true,
getSerializedStateForChild: () => {
const basemapLayerDescriptor = createBasemapLayerDescriptor();
const intialLayers = basemapLayerDescriptor ? [basemapLayerDescriptor] : [];
Expand All @@ -66,7 +67,6 @@ export function PassiveMap(props: Props) {
hidePanelTitles: true,
viewMode: ViewMode.VIEW,
isLayerTOCOpen: false,
hideFilterActions: true,
mapSettings: {
disableInteractive: false,
hideToolbarOverlay: false,
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ import { VectorTileInspectorView } from './inspector/vector_tile_adapter/vector_
import { PassiveMapLazy, setupLensChoroplethChart } from './lens';
import { CONTENT_ID, LATEST_VERSION } from '../common/content_management';
import { setupMapEmbeddable } from './react_embeddable/setup_map_embeddable';
import { MapRendererLazy } from './react_embeddable/map_renderer_lazy';
import { MapRendererLazy } from './react_embeddable/map_renderer/map_renderer_lazy';

export interface MapsPluginSetupDependencies {
cloud?: CloudSetup;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ import { initializeDataViews } from './initialize_data_views';
import { initializeFetch } from './initialize_fetch';
import { initializeEditApi } from './initialize_edit_api';
import { extractReferences } from '../../common/migrations/references';
import { MapAttributes } from '../../common/content_management';
import { MapSettings } from '../../common/descriptor_types';
import { isMapRendererApi } from './map_renderer/types';

export function getControlledBy(id: string) {
return `mapEmbeddablePanel${id}`;
Expand All @@ -65,6 +68,10 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory<
});
await savedMap.whenReady();

const attributes$ = new BehaviorSubject<MapAttributes | undefined>(state.attributes);
const mapSettings$ = new BehaviorSubject<Partial<MapSettings> | undefined>(state.mapSettings);
const savedObjectId$ = new BehaviorSubject<string | undefined>(state.savedObjectId);

// eslint bug, eslint thinks api is never reassigned even though it is
// eslint-disable-next-line prefer-const
let api: MapApi | undefined;
Expand Down Expand Up @@ -171,14 +178,14 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory<
}),
...crossPanelActions.comparators,
...reduxSync.comparators,
attributes: [attributes$, (next: MapAttributes | undefined) => attributes$.next(next)],
mapSettings: [
mapSettings$,
(next: Partial<MapSettings> | undefined) => mapSettings$.next(next),
],
savedObjectId: [savedObjectId$, (next: string | undefined) => savedObjectId$.next(next)],
// readonly comparators
attributes: getUnchangingComparator(),
mapBuffer: getUnchangingComparator(),
savedObjectId: getUnchangingComparator(),
mapSettings: getUnchangingComparator(),
hideFilterActions: getUnchangingComparator(),
isSharable: getUnchangingComparator(),
tooltipRenderer: getUnchangingComparator(),
}
);

Expand Down Expand Up @@ -229,17 +236,28 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory<
<MapContainer
onSingleValueTrigger={actionHandlers.onSingleValueTrigger}
addFilters={
state.hideFilterActions || areTriggersDisabled(api)
(isMapRendererApi(parentApi) &&
typeof parentApi.hideFilterActions === 'boolean' &&
parentApi.hideFilterActions) ||
areTriggersDisabled(api)
? null
: actionHandlers.addFilters
}
getFilterActions={actionHandlers.getFilterActions}
getActionContext={actionHandlers.getActionContext}
renderTooltipContent={state.tooltipRenderer}
renderTooltipContent={
isMapRendererApi(parentApi) && parentApi.getTooltipRenderer
? parentApi.getTooltipRenderer()
: undefined
}
title={panelTitle ?? defaultPanelTitle}
description={panelDescription ?? defaultPanelDescription}
waitUntilTimeLayersLoad$={waitUntilTimeLayersLoad$(savedMap.getStore())}
isSharable={state.isSharable ?? true}
isSharable={
isMapRendererApi(parentApi) && typeof parentApi.isSharable === 'boolean'
? parentApi.isSharable
: true
}
/>
</Provider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import React, { useEffect, useRef } from 'react';
import type { Filter, Query, TimeRange } from '@kbn/es-query';
import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public';
import { useSearchApi } from '@kbn/presentation-publishing';
import type { LayerDescriptor, MapCenterAndZoom, MapSettings } from '../../common/descriptor_types';
import { createBasemapLayerDescriptor } from '../classes/layers/create_basemap_layer_descriptor';
import { MapApi, MapRuntimeState, MapSerializedState } from './types';
import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
import { RenderToolTipContent } from '../classes/tooltips/tooltip_property';
import type {
LayerDescriptor,
MapCenterAndZoom,
MapSettings,
} from '../../../common/descriptor_types';
import { createBasemapLayerDescriptor } from '../../classes/layers/create_basemap_layer_descriptor';
import { MapApi, MapRuntimeState, MapSerializedState } from '../types';
import { MAP_SAVED_OBJECT_TYPE } from '../../../common/constants';
import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property';
import { MAP_RENDERER_TYPE } from './types';

function getLayers(layerList: LayerDescriptor[]) {
const basemapLayer = createBasemapLayerDescriptor();
Expand Down Expand Up @@ -61,30 +66,27 @@ export function MapRenderer(props: Props) {
<ReactEmbeddableRenderer<MapSerializedState, MapRuntimeState, MapApi>
type={MAP_SAVED_OBJECT_TYPE}
getParentApi={() => ({
...searchApi,
type: MAP_RENDERER_TYPE,
getTooltipRenderer: props.getTooltipRenderer,
hideFilterActions: props.hideFilterActions,
isSharable: props.isSharable,
getSerializedStateForChild: () => {
const rawState: MapSerializedState = {
attributes: {
title: props.title ?? '',
layerListJSON: JSON.stringify(getLayers(props.layerList)),
},
hidePanelTitles: !Boolean(props.title),
isLayerTOCOpen:
typeof props.isLayerTOCOpen === 'boolean' ? props.isLayerTOCOpen : false,
hideFilterActions:
typeof props.hideFilterActions === 'boolean' ? props.hideFilterActions : false,
mapCenter: props.mapCenter,
mapSettings: props.mapSettings ?? {},
isSharable: props.isSharable,
};
if (props.getTooltipRenderer) {
rawState.tooltipRenderer = props.getTooltipRenderer();
}
return {
rawState,
rawState: {
attributes: {
title: props.title ?? '',
layerListJSON: JSON.stringify(getLayers(props.layerList)),
},
hidePanelTitles: !Boolean(props.title),
isLayerTOCOpen:
typeof props.isLayerTOCOpen === 'boolean' ? props.isLayerTOCOpen : false,
mapCenter: props.mapCenter,
mapSettings: props.mapSettings ?? {},
},
references: [],
};
},
...searchApi,
})}
onApiAvailable={(api) => {
mapApiRef.current = api;
Expand Down
21 changes: 21 additions & 0 deletions x-pack/plugins/maps/public/react_embeddable/map_renderer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { HasType, apiIsOfType } from '@kbn/presentation-publishing';
import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property';

export const MAP_RENDERER_TYPE = 'mapRenderer';

export type MapRendererApi = HasType<typeof MAP_RENDERER_TYPE> & {
getTooltipRenderer?: () => RenderToolTipContent;
hideFilterActions?: boolean;
isSharable?: boolean;
};

export function isMapRendererApi(api: unknown): api is MapRendererApi {
return Boolean(api && apiIsOfType(api, MAP_RENDERER_TYPE));
}
7 changes: 0 additions & 7 deletions x-pack/plugins/maps/public/react_embeddable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import {
MapSettings,
} from '../../common/descriptor_types';
import { ILayer } from '../classes/layers/layer';
import { RenderToolTipContent } from '../classes/tooltips/tooltip_property';
import { EventHandlers } from '../reducers/non_serializable_instances';

export type MapSerializedState = SerializedTitles &
Expand All @@ -47,15 +46,9 @@ export type MapSerializedState = SerializedTitles &
mapBuffer?: MapExtent;
mapSettings?: Partial<MapSettings>;
hiddenLayers?: string[];
hideFilterActions?: boolean;
timeRange?: TimeRange;
filterByMapExtent?: boolean;
isMovementSynchronized?: boolean;

// Configuration item that are never persisted
// Putting in state as a temporary work around
isSharable?: boolean;
tooltipRenderer?: RenderToolTipContent;
};

export type MapRuntimeState = MapSerializedState;
Expand Down

0 comments on commit a8ebc7f

Please sign in to comment.