mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[8.x] [maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard (#193629) (#193797)
# Backport This will backport the following commits from `main` to `8.x`: - [[maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard (#193629)](https://github.com/elastic/kibana/pull/193629) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Nathan Reese","email":"reese.nathan@elastic.co"},"sourceCommit":{"committedDate":"2024-09-23T20:58:09Z","message":"[maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard (#193629)\n\nCloses https://github.com/elastic/kibana/issues/190468 and\r\nhttps://github.com/elastic/kibana/issues/193601\r\n\r\nDashboard unsaved changes for a panel are obtained from the embeddable\r\ncomparator subject for each comparator. If comparator subject does not\r\nreturn a value, then this information is lost when returning to a\r\ndashboard with unsaved changes. This is why layers and filters where\r\ndisappearing from a map when returning to a dashboard with unsaved\r\nchanges. This PR resolves this issue by providing comparator subjects\r\nand setters for `savedObjectId`, `attributes`, and `mapSettings`.\r\n\r\nPR also resolves issue of passing props from `MapRenderer` component\r\ninto map embeddable. Instead of passing props via state, props should be\r\npassed from `MapRenderer` parent api.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"a8ebc7f4686e359e9893e7e6fed291711c38dad4","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","Team:Presentation","v9.0.0","Feature:Maps","v8.16.0","backport:version","v8.15.3"],"title":"[maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard","number":193629,"url":"https://github.com/elastic/kibana/pull/193629","mergeCommit":{"message":"[maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard (#193629)\n\nCloses https://github.com/elastic/kibana/issues/190468 and\r\nhttps://github.com/elastic/kibana/issues/193601\r\n\r\nDashboard unsaved changes for a panel are obtained from the embeddable\r\ncomparator subject for each comparator. If comparator subject does not\r\nreturn a value, then this information is lost when returning to a\r\ndashboard with unsaved changes. This is why layers and filters where\r\ndisappearing from a map when returning to a dashboard with unsaved\r\nchanges. This PR resolves this issue by providing comparator subjects\r\nand setters for `savedObjectId`, `attributes`, and `mapSettings`.\r\n\r\nPR also resolves issue of passing props from `MapRenderer` component\r\ninto map embeddable. Instead of passing props via state, props should be\r\npassed from `MapRenderer` parent api.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"a8ebc7f4686e359e9893e7e6fed291711c38dad4"}},"sourceBranch":"main","suggestedTargetBranches":["8.x","8.15"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193629","number":193629,"mergeCommit":{"message":"[maps embeddable] fix map layers disappear from map panel when using session storage to continue editing a dashboard (#193629)\n\nCloses https://github.com/elastic/kibana/issues/190468 and\r\nhttps://github.com/elastic/kibana/issues/193601\r\n\r\nDashboard unsaved changes for a panel are obtained from the embeddable\r\ncomparator subject for each comparator. If comparator subject does not\r\nreturn a value, then this information is lost when returning to a\r\ndashboard with unsaved changes. This is why layers and filters where\r\ndisappearing from a map when returning to a dashboard with unsaved\r\nchanges. This PR resolves this issue by providing comparator subjects\r\nand setters for `savedObjectId`, `attributes`, and `mapSettings`.\r\n\r\nPR also resolves issue of passing props from `MapRenderer` component\r\ninto map embeddable. Instead of passing props via state, props should be\r\npassed from `MapRenderer` parent api.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>","sha":"a8ebc7f4686e359e9893e7e6fed291711c38dad4"}},{"branch":"8.x","label":"v8.16.0","branchLabelMappingKey":"^v8.16.0$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.15","label":"v8.15.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Nathan Reese <reese.nathan@elastic.co>
This commit is contained in:
parent
b9c29e9bfa
commit
58480def90
10 changed files with 79 additions and 45 deletions
|
@ -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: {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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] : [];
|
||||
|
@ -66,7 +67,6 @@ export function PassiveMap(props: Props) {
|
|||
hidePanelTitles: true,
|
||||
viewMode: ViewMode.VIEW,
|
||||
isLayerTOCOpen: false,
|
||||
hideFilterActions: true,
|
||||
mapSettings: {
|
||||
disableInteractive: false,
|
||||
hideToolbarOverlay: false,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}`;
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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();
|
||||
|
@ -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;
|
|
@ -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));
|
||||
}
|
|
@ -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 &
|
||||
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue