From fb911faa2e7936604c5362d5041507f41d518625 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 4 Apr 2025 13:50:36 -0600 Subject: [PATCH 1/6] map embeddable --- .../eui_markdown_react_embeddable.tsx | 1 + .../initialize_cross_panel_actions.ts | 9 +- .../react_embeddable/initialize_redux_sync.ts | 74 ++++----- .../react_embeddable/map_react_embeddable.tsx | 151 ++++++++++-------- .../react_embeddable/setup_map_embeddable.ts | 9 +- .../maps/public/react_embeddable/types.ts | 2 - 6 files changed, 125 insertions(+), 121 deletions(-) diff --git a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx index 2f68f46892893..1ffceb3d34511 100644 --- a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx @@ -73,6 +73,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< return { ...titleComparators, ...markdownComparators }; }, onReset: (lastSaved) => { + debugger; /** * if this embeddable had a difference between its runtime and serialized state, we could run the 'deserializeState' * function here before resetting. onReset can be async so to support a potential async deserialize function. diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts index 69a304dd40501..51fcc985e3021 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts @@ -30,6 +30,11 @@ import { getGeoFieldsLabel } from './get_geo_fields_label'; import { MapApi, MapSerializedState } from './types'; import { setOnMapMove } from '../reducers/non_serializable_instances'; +export const crossPanelActionComparators: StateComparators> = { + isMovementSynchronized: 'referenceEquality', + filterByMapExtent: 'referenceEquality' +}; + export function initializeCrossPanelActions({ controlledBy, getActionContext, @@ -213,10 +218,6 @@ export function initializeCrossPanelActions({ mapEmbeddablesSingleton.unregister(uuid); unsubscribeFromStore(); }, - comparators: { - isMovementSynchronized: [isMovementSynchronized$, setIsMovementSynchronized], - filterByMapExtent: [isFilterByMapExtent$, setIsFilterByMapExtent], - } as StateComparators>, getIsFilterByMapExtent, serialize: () => { return { diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts index cd4117745a4ad..13518a1e6c1b3 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { BehaviorSubject, debounceTime, filter, map, Subscription } from 'rxjs'; +import { BehaviorSubject, combineLatest, debounceTime, filter, map, Subscription } from 'rxjs'; import fastIsEqual from 'fast-deep-equal'; import { PublishingSubject, StateComparators } from '@kbn/presentation-publishing'; import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; @@ -58,6 +58,23 @@ function getHiddenLayerIds(state: MapStoreState) { .map((layer) => layer.id); } +export const reduxSyncComparators: StateComparators> = { + hiddenLayers: 'deepEquality', + isLayerTOCOpen: 'referenceEquality', + mapCenter: (a, b) => { + if (!a || !b) { + return a === b; + } + + if (a.lat !== b.lat) return false; + if (a.lon !== b.lon) return false; + // Map may not restore reset zoom exactly + return Math.abs(a.zoom - b.zoom) < 0.05; + }, + mapBuffer: 'skip', + openTOCDetails: 'deepEquality', +}; + export function initializeReduxSync({ savedMap, state, @@ -199,48 +216,19 @@ export function initializeReduxSync({ store.dispatch(setEventHandlers(eventHandlers)); }, }, - comparators: { - // mapBuffer comparator intentionally omitted and is not part of unsaved changes check - hiddenLayers: [ - hiddenLayers$, - (nextValue: string[]) => { - store.dispatch(setHiddenLayers(nextValue)); - }, - fastIsEqual, - ], - isLayerTOCOpen: [ - isLayerTOCOpen$, - (nextValue: boolean) => { - store.dispatch(setIsLayerTOCOpen(nextValue)); - }, - ], - mapCenter: [ - mapCenterAndZoom$, - (nextValue: MapCenterAndZoom) => { - store.dispatch(setGotoWithCenter(nextValue)); - }, - (a, b) => { - if (!a || !b) { - return a === b; - } - - if (a.lat !== b.lat) return false; - if (a.lon !== b.lon) return false; - // Map may not restore reset zoom exactly - return Math.abs(a.zoom - b.zoom) < 0.05; - }, - ], - openTOCDetails: [ - openTOCDetails$, - (nextValue: string[]) => { - store.dispatch(setOpenTOCDetails(nextValue)); - }, - fastIsEqual, - ], - } as StateComparators< - Pick - >, - serialize: () => { + latestState$: combineLatest([ + hiddenLayers$, + isLayerTOCOpen$, + mapCenterAndZoom$, + openTOCDetails$, + ]), + reinitializeState: (lastSaved: MapSerializedState) => { + store.dispatch(setHiddenLayers(lastSaved.hiddenLayers ?? [])); + store.dispatch(setIsLayerTOCOpen(lastSaved.isLayerTOCOpen ?? true)); + if (lastSaved.mapCenter) store.dispatch(setGotoWithCenter(lastSaved.mapCenter)); + store.dispatch(setOpenTOCDetails(lastSaved.openTOCDetails)); + }, + getLatestState: () => { return { hiddenLayers: getHiddenLayerIds(store.getState()), isLayerTOCOpen: getIsLayerTOCOpen(store.getState()), diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx index d1f861ace715d..2af80d6926940 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx @@ -9,23 +9,24 @@ import React, { useEffect } from 'react'; import { Provider } from 'react-redux'; import { EuiEmptyPrompt } from '@elastic/eui'; import { APPLY_FILTER_TRIGGER } from '@kbn/data-plugin/public'; -import { ReactEmbeddableFactory, VALUE_CLICK_TRIGGER } from '@kbn/embeddable-plugin/public'; +import { EmbeddableFactory, VALUE_CLICK_TRIGGER } from '@kbn/embeddable-plugin/public'; import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; import { + SerializedPanelState, apiIsOfType, areTriggersDisabled, - getUnchangingComparator, - initializeTimeRange, + initializeTimeRangeManager, initializeTitleManager, + titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { apiPublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; import { inject } from '../../common/embeddable'; -import type { MapApi, MapRuntimeState, MapSerializedState } from './types'; +import type { MapApi, MapSerializedState } from './types'; import { SavedMap } from '../routes/map_page'; -import { initializeReduxSync } from './initialize_redux_sync'; +import { initializeReduxSync, reduxSyncComparators } from './initialize_redux_sync'; import { getByReferenceState, getByValueState, @@ -35,7 +36,7 @@ import { getEmbeddableEnhanced, getSpacesApi } from '../kibana_services'; import { initializeActionHandlers } from './initialize_action_handlers'; import { MapContainer } from '../connected_components/map_container'; import { waitUntilTimeLayersLoad$ } from '../routes/map_page/map_app/wait_until_time_layers_load'; -import { initializeCrossPanelActions } from './initialize_cross_panel_actions'; +import { crossPanelActionComparators, initializeCrossPanelActions } from './initialize_cross_panel_actions'; import { initializeDataViews } from './initialize_data_views'; import { initializeFetch } from './initialize_fetch'; import { initializeEditApi } from './initialize_edit_api'; @@ -43,34 +44,32 @@ import { extractReferences } from '../../common/migrations/references'; import { MapAttributes } from '../../common/content_management'; import { MapSettings } from '../../common/descriptor_types'; import { isMapRendererApi } from './map_renderer/types'; +import { initializeUnsavedChanges } from '@kbn/presentation-containers'; +import { timeRangeComparators } from '@kbn/presentation-publishing/interfaces/fetch/time_range_manager'; export function getControlledBy(id: string) { return `mapEmbeddablePanel${id}`; } -export const mapEmbeddableFactory: ReactEmbeddableFactory< - MapSerializedState, - MapRuntimeState, - MapApi -> = { +function deserializeState(state: SerializedPanelState) { + return state.rawState + ? (inject( + state.rawState as EmbeddableStateWithType, + state.references ?? [] + ) as unknown as MapSerializedState) + : {}; +} + +export const mapEmbeddableFactory: EmbeddableFactory = { type: MAP_SAVED_OBJECT_TYPE, - deserializeState: (state) => { - return state.rawState - ? (inject( - state.rawState as EmbeddableStateWithType, - state.references ?? [] - ) as unknown as MapSerializedState) - : {}; - }, - buildEmbeddable: async (state, buildApi, uuid, parentApi) => { - const savedMap = new SavedMap({ - mapSerializedState: state, - }); + buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + const mapSerializedState = deserializeState(initialState); + const savedMap = new SavedMap({ mapSerializedState }); await savedMap.whenReady(); - const attributes$ = new BehaviorSubject(state.attributes); - const mapSettings$ = new BehaviorSubject | undefined>(state.mapSettings); - const savedObjectId$ = new BehaviorSubject(state.savedObjectId); + const attributes$ = new BehaviorSubject(mapSerializedState.attributes); + const mapSettings$ = new BehaviorSubject | undefined>(mapSerializedState.mapSettings); + const savedObjectId$ = new BehaviorSubject(mapSerializedState.savedObjectId); // eslint bug, eslint thinks api is never reassigned even though it is // eslint-disable-next-line prefer-const @@ -79,12 +78,12 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< const sharingSavedObjectProps = savedMap.getSharingSavedObjectProps(); const spaces = getSpacesApi(); const controlledBy = getControlledBy(uuid); - const titleManager = initializeTitleManager(state); - const timeRange = initializeTimeRange(state); + const titleManager = initializeTitleManager(mapSerializedState); + const timeRangeManager = initializeTimeRangeManager(mapSerializedState); const dynamicActionsApi = getEmbeddableEnhanced()?.initializeReactEmbeddableDynamicActions( uuid, () => titleManager.api.title$.getValue(), - state + mapSerializedState ); const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); @@ -94,7 +93,7 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< ); const reduxSync = initializeReduxSync({ savedMap, - state, + state: mapSerializedState, syncColors$: apiPublishesSettings(parentApi) ? parentApi.settings.syncColors$ : undefined, uuid, }); @@ -103,19 +102,19 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< controlledBy, getActionContext: actionHandlers.getActionContext, getApi, - state, + state: mapSerializedState, savedMap, uuid, }); function getState() { return { - ...state, - ...timeRange.serialize(), - ...titleManager.serialize(), + ...mapSerializedState, + ...timeRangeManager.getLatestState(), + ...titleManager.getLatestState(), ...(dynamicActionsApi?.serializeDynamicActions() ?? {}), ...crossPanelActions.serialize(), - ...reduxSync.serialize(), + ...reduxSync.getLatestState(), }; } @@ -152,46 +151,58 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< }; } - api = buildApi( - { - defaultTitle$, - defaultDescription$, - ...timeRange.api, - ...(dynamicActionsApi?.dynamicActionsApi ?? {}), - ...titleManager.api, - ...reduxSync.api, - ...initializeEditApi(uuid, getState, parentApi, state.savedObjectId), - ...initializeLibraryTransforms(savedMap, serializeState), - ...initializeDataViews(savedMap.getStore()), - serializeState, - supportedTriggers: () => { - return [APPLY_FILTER_TRIGGER, VALUE_CLICK_TRIGGER]; - }, + const unsavedChangesApi = initializeUnsavedChanges({ + uuid, + parentApi, + serializeState, + latestRuntimeState$: combineLatest([ + reduxSync.latestState$, + titleManager.latestState$, + timeRangeManager.latestState$, + ]), + getComparators: () => { + return { + ...crossPanelActionComparators, + ...reduxSyncComparators, + ...titleComparators, + ...timeRangeComparators, + attributes: 'referenceEquality', + enhancements: 'skip', + mapSettings: 'referenceEquality', + savedObjectId: 'referenceEquality', + }; + }, + onReset: (lastSaved) => { + attributes$.next(lastSaved?.attributes); + mapSettings$.next(lastSaved?.mapSettings); + savedObjectId$.next(lastSaved?.savedObjectId); + reduxSync.reinitializeState(lastSaved); + titleManager.reinitializeState(lastSaved); + }, + }); + + api = finalizeApi({ + defaultTitle$, + defaultDescription$, + ...unsavedChangesApi, + ...timeRangeManager.api, + ...(dynamicActionsApi?.dynamicActionsApi ?? {}), + ...titleManager.api, + ...reduxSync.api, + ...initializeEditApi(uuid, getState, parentApi, mapSerializedState.savedObjectId), + ...initializeLibraryTransforms(savedMap, serializeState), + ...initializeDataViews(savedMap.getStore()), + serializeState, + supportedTriggers: () => { + return [APPLY_FILTER_TRIGGER, VALUE_CLICK_TRIGGER]; }, - { - ...timeRange.comparators, - ...titleManager.comparators, - ...(dynamicActionsApi?.dynamicActionsComparator ?? { - enhancements: getUnchangingComparator(), - }), - ...crossPanelActions.comparators, - ...reduxSync.comparators, - attributes: [attributes$, (next: MapAttributes | undefined) => attributes$.next(next)], - mapSettings: [ - mapSettings$, - (next: Partial | undefined) => mapSettings$.next(next), - ], - savedObjectId: [savedObjectId$, (next: string | undefined) => savedObjectId$.next(next)], - // readonly comparators - mapBuffer: getUnchangingComparator(), - } - ); + }); const unsubscribeFromFetch = initializeFetch({ api, controlledBy, getIsFilterByMapExtent: crossPanelActions.getIsFilterByMapExtent, - searchSessionMapBuffer: state.mapBuffer, + searchSessionMapBuffer: mapSerializedState.mapBuffer, store: savedMap.getStore(), }); diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts index 8821941911447..d88958e41be59 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { MapAttributes } from '../../common/content_management'; import { MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants'; import { untilPluginStartServicesReady } from '../kibana_services'; +import { MapSerializedState } from './types'; export function setupMapEmbeddable(embeddableSetup: EmbeddableSetup) { embeddableSetup.registerReactEmbeddableFactory(MAP_SAVED_OBJECT_TYPE, async () => { @@ -24,9 +25,13 @@ export function setupMapEmbeddable(embeddableSetup: EmbeddableSetup) { embeddableSetup.registerAddFromLibraryType({ onAdd: (container, savedObject) => { - container.addNewPanel({ + container.addNewPanel({ panelType: MAP_SAVED_OBJECT_TYPE, - initialState: { savedObjectId: savedObject.id }, + serializedState: { + rawState: { + savedObjectId: savedObject.id + }, + }, }); }, savedObjectType: MAP_SAVED_OBJECT_TYPE, diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts index f8538e14e2104..7ecc04cb896a3 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts @@ -49,8 +49,6 @@ export type MapSerializedState = SerializedTitles & isMovementSynchronized?: boolean; }; -export type MapRuntimeState = MapSerializedState; - export type MapApi = DefaultEmbeddableApi & HasDynamicActions & Partial & From fcaae06115b9faf2bf26089297c451889c803479 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Fri, 4 Apr 2025 14:13:39 -0600 Subject: [PATCH 2/6] clean up --- .../initialize_cross_panel_actions.ts | 19 +++++--- .../react_embeddable/initialize_redux_sync.ts | 17 ++++--- .../react_embeddable/map_react_embeddable.tsx | 47 ++++++++++--------- .../react_embeddable/setup_map_embeddable.ts | 4 +- .../maps/public/react_embeddable/types.ts | 6 +-- 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts index 51fcc985e3021..761c8346921b9 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts @@ -9,7 +9,7 @@ import _ from 'lodash'; import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public'; import { i18n } from '@kbn/i18n'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { getTitle, StateComparators } from '@kbn/presentation-publishing'; import { createExtentFilter } from '../../common/elasticsearch_util'; import { SavedMap } from '../routes/map_page'; @@ -30,9 +30,11 @@ import { getGeoFieldsLabel } from './get_geo_fields_label'; import { MapApi, MapSerializedState } from './types'; import { setOnMapMove } from '../reducers/non_serializable_instances'; -export const crossPanelActionComparators: StateComparators> = { +export const crossPanelActionsComparators: StateComparators< + Pick +> = { isMovementSynchronized: 'referenceEquality', - filterByMapExtent: 'referenceEquality' + filterByMapExtent: 'referenceEquality', }; export function initializeCrossPanelActions({ @@ -56,7 +58,7 @@ export function initializeCrossPanelActions({ function getIsMovementSynchronized() { return isMovementSynchronized$.value ?? true; } - function setIsMovementSynchronized(next: boolean) { + function setIsMovementSynchronized(next: boolean | undefined) { isMovementSynchronized$.next(next); } @@ -64,7 +66,7 @@ export function initializeCrossPanelActions({ function getIsFilterByMapExtent() { return isFilterByMapExtent$.value ?? false; } - function setIsFilterByMapExtent(next: boolean) { + function setIsFilterByMapExtent(next: boolean | undefined) { isFilterByMapExtent$.next(next); } @@ -219,7 +221,12 @@ export function initializeCrossPanelActions({ unsubscribeFromStore(); }, getIsFilterByMapExtent, - serialize: () => { + latestState$: combineLatest([isMovementSynchronized$, isFilterByMapExtent$]), + reinitializeState: (lastSaved: MapSerializedState) => { + setIsMovementSynchronized(lastSaved.isMovementSynchronized); + setIsFilterByMapExtent(lastSaved.filterByMapExtent); + }, + getLatestState: () => { return { isMovementSynchronized: isMovementSynchronized$.value, filterByMapExtent: isFilterByMapExtent$.value, diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts index 13518a1e6c1b3..d5e6d0d6ae4ad 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts @@ -58,7 +58,12 @@ function getHiddenLayerIds(state: MapStoreState) { .map((layer) => layer.id); } -export const reduxSyncComparators: StateComparators> = { +export const reduxSyncComparators: StateComparators< + Pick< + MapSerializedState, + 'hiddenLayers' | 'isLayerTOCOpen' | 'mapCenter' | 'mapBuffer' | 'openTOCDetails' + > +> = { hiddenLayers: 'deepEquality', isLayerTOCOpen: 'referenceEquality', mapCenter: (a, b) => { @@ -222,11 +227,11 @@ export function initializeReduxSync({ mapCenterAndZoom$, openTOCDetails$, ]), - reinitializeState: (lastSaved: MapSerializedState) => { - store.dispatch(setHiddenLayers(lastSaved.hiddenLayers ?? [])); - store.dispatch(setIsLayerTOCOpen(lastSaved.isLayerTOCOpen ?? true)); - if (lastSaved.mapCenter) store.dispatch(setGotoWithCenter(lastSaved.mapCenter)); - store.dispatch(setOpenTOCDetails(lastSaved.openTOCDetails)); + reinitializeState: (lastSaved?: MapSerializedState) => { + store.dispatch(setHiddenLayers(lastSaved?.hiddenLayers ?? [])); + store.dispatch(setIsLayerTOCOpen(lastSaved?.isLayerTOCOpen ?? true)); + if (lastSaved?.mapCenter) store.dispatch(setGotoWithCenter(lastSaved.mapCenter)); + store.dispatch(setOpenTOCDetails(lastSaved?.openTOCDetails)); }, getLatestState: () => { return { diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx index 2af80d6926940..5f1ce2bce0ddd 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx @@ -12,7 +12,6 @@ import { APPLY_FILTER_TRIGGER } from '@kbn/data-plugin/public'; import { EmbeddableFactory, VALUE_CLICK_TRIGGER } from '@kbn/embeddable-plugin/public'; import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; import { - SerializedPanelState, apiIsOfType, areTriggersDisabled, initializeTimeRangeManager, @@ -22,6 +21,8 @@ import { } from '@kbn/presentation-publishing'; import { BehaviorSubject, combineLatest } from 'rxjs'; import { apiPublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; +import { initializeUnsavedChanges } from '@kbn/presentation-containers'; +import { timeRangeComparators } from '@kbn/presentation-publishing/interfaces/fetch/time_range_manager'; import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants'; import { inject } from '../../common/embeddable'; import type { MapApi, MapSerializedState } from './types'; @@ -36,7 +37,10 @@ import { getEmbeddableEnhanced, getSpacesApi } from '../kibana_services'; import { initializeActionHandlers } from './initialize_action_handlers'; import { MapContainer } from '../connected_components/map_container'; import { waitUntilTimeLayersLoad$ } from '../routes/map_page/map_app/wait_until_time_layers_load'; -import { crossPanelActionComparators, initializeCrossPanelActions } from './initialize_cross_panel_actions'; +import { + crossPanelActionsComparators, + initializeCrossPanelActions, +} from './initialize_cross_panel_actions'; import { initializeDataViews } from './initialize_data_views'; import { initializeFetch } from './initialize_fetch'; import { initializeEditApi } from './initialize_edit_api'; @@ -44,32 +48,32 @@ import { extractReferences } from '../../common/migrations/references'; import { MapAttributes } from '../../common/content_management'; import { MapSettings } from '../../common/descriptor_types'; import { isMapRendererApi } from './map_renderer/types'; -import { initializeUnsavedChanges } from '@kbn/presentation-containers'; -import { timeRangeComparators } from '@kbn/presentation-publishing/interfaces/fetch/time_range_manager'; export function getControlledBy(id: string) { return `mapEmbeddablePanel${id}`; } -function deserializeState(state: SerializedPanelState) { - return state.rawState - ? (inject( - state.rawState as EmbeddableStateWithType, - state.references ?? [] - ) as unknown as MapSerializedState) - : {}; -} - export const mapEmbeddableFactory: EmbeddableFactory = { type: MAP_SAVED_OBJECT_TYPE, buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { - const mapSerializedState = deserializeState(initialState); + const mapSerializedState = initialState.rawState + ? (inject( + initialState.rawState as EmbeddableStateWithType, + initialState.references ?? [] + ) as unknown as MapSerializedState) + : {}; const savedMap = new SavedMap({ mapSerializedState }); await savedMap.whenReady(); - const attributes$ = new BehaviorSubject(mapSerializedState.attributes); - const mapSettings$ = new BehaviorSubject | undefined>(mapSerializedState.mapSettings); - const savedObjectId$ = new BehaviorSubject(mapSerializedState.savedObjectId); + const attributes$ = new BehaviorSubject( + mapSerializedState.attributes + ); + const mapSettings$ = new BehaviorSubject | undefined>( + mapSerializedState.mapSettings + ); + const savedObjectId$ = new BehaviorSubject( + mapSerializedState.savedObjectId + ); // eslint bug, eslint thinks api is never reassigned even though it is // eslint-disable-next-line prefer-const @@ -113,7 +117,7 @@ export const mapEmbeddableFactory: EmbeddableFactory ...timeRangeManager.getLatestState(), ...titleManager.getLatestState(), ...(dynamicActionsApi?.serializeDynamicActions() ?? {}), - ...crossPanelActions.serialize(), + ...crossPanelActions.getLatestState(), ...reduxSync.getLatestState(), }; } @@ -151,18 +155,19 @@ export const mapEmbeddableFactory: EmbeddableFactory }; } - const unsavedChangesApi = initializeUnsavedChanges({ + const unsavedChangesApi = initializeUnsavedChanges({ uuid, parentApi, - serializeState, + serializeState: getState, latestRuntimeState$: combineLatest([ + crossPanelActions.latestState$, reduxSync.latestState$, titleManager.latestState$, timeRangeManager.latestState$, ]), getComparators: () => { return { - ...crossPanelActionComparators, + ...crossPanelActionsComparators, ...reduxSyncComparators, ...titleComparators, ...timeRangeComparators, diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts index d88958e41be59..e6eb53a8b8120 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/setup_map_embeddable.ts @@ -27,9 +27,9 @@ export function setupMapEmbeddable(embeddableSetup: EmbeddableSetup) { onAdd: (container, savedObject) => { container.addNewPanel({ panelType: MAP_SAVED_OBJECT_TYPE, - serializedState: { + serializedState: { rawState: { - savedObjectId: savedObject.id + savedObjectId: savedObject.id, }, }, }); diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts index 7ecc04cb896a3..1c751c4554d30 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/types.ts @@ -6,7 +6,6 @@ */ import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; import type { HasInspectorAdapters } from '@kbn/inspector-plugin/public'; import type { HasEditCapabilities, @@ -16,6 +15,7 @@ import type { PublishesDataLoading, PublishesDataViews, PublishesUnifiedSearch, + SerializedTimeRange, SerializedTitles, } from '@kbn/presentation-publishing'; import type { HasDynamicActions } from '@kbn/embeddable-enhanced-plugin/public'; @@ -31,7 +31,8 @@ import type { import type { ILayer } from '../classes/layers/layer'; import type { EventHandlers } from '../reducers/non_serializable_instances'; -export type MapSerializedState = SerializedTitles & +export type MapSerializedState = SerializedTimeRange & + SerializedTitles & Partial & { // by-value attributes?: MapAttributes; @@ -44,7 +45,6 @@ export type MapSerializedState = SerializedTitles & mapBuffer?: MapExtent; mapSettings?: Partial; hiddenLayers?: string[]; - timeRange?: TimeRange; filterByMapExtent?: boolean; isMovementSynchronized?: boolean; }; From 53d5ea855d4ec223c69e96ccbe22d2a9a22c2c85 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Sat, 5 Apr 2025 09:15:48 -0600 Subject: [PATCH 3/6] dynamic actions --- .../embeddable_enhanced/public/mocks.ts | 2 +- .../embeddable_enhanced/public/plugin.ts | 51 +++++++++---------- .../react_embeddable/map_react_embeddable.tsx | 18 ++++--- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/x-pack/platform/plugins/shared/embeddable_enhanced/public/mocks.ts b/x-pack/platform/plugins/shared/embeddable_enhanced/public/mocks.ts index 37845a9ff0a1e..a3783cca71542 100644 --- a/x-pack/platform/plugins/shared/embeddable_enhanced/public/mocks.ts +++ b/x-pack/platform/plugins/shared/embeddable_enhanced/public/mocks.ts @@ -18,7 +18,7 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const startContract: Start = { - initializeReactEmbeddableDynamicActions: jest.fn(), + initializeEmbeddableDynamicActions: jest.fn(), }; return startContract; diff --git a/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts b/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts index 0e374070c00d1..2bca05c0a81c2 100644 --- a/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts +++ b/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts @@ -19,7 +19,7 @@ import { UiActionsEnhancedDynamicActionManager as DynamicActionManager, } from '@kbn/ui-actions-enhanced-plugin/public'; import deepEqual from 'react-fast-compare'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, Observable, map } from 'rxjs'; import { DynamicActionStorage, type DynamicActionStorageApi, @@ -40,19 +40,21 @@ export interface StartDependencies { // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface SetupContract {} -export interface ReactEmbeddableDynamicActionsApi { - dynamicActionsApi: HasDynamicActions; - dynamicActionsComparator: StateComparators; - serializeDynamicActions: () => DynamicActionsSerializedState; +export interface EmbeddableDynamicActionsManager { + api: HasDynamicActions; + comparators: StateComparators; + latestState$: Observable; + getLatestState: () => DynamicActionsSerializedState; + reinitializeState: (lastState: DynamicActionsSerializedState) => void; startDynamicActions: () => { stopDynamicActions: () => void }; } export interface StartContract { - initializeReactEmbeddableDynamicActions: ( + initializeEmbeddableDynamicActions: ( uuid: string, getTitle: () => string | undefined, state: DynamicActionsSerializedState - ) => ReactEmbeddableDynamicActionsApi; + ) => EmbeddableDynamicActionsManager; } export interface DynamicActionsSerializedState { @@ -74,7 +76,7 @@ export class EmbeddableEnhancedPlugin this.uiActions = plugins.uiActionsEnhanced; return { - initializeReactEmbeddableDynamicActions: this.initializeDynamicActions.bind(this), + initializeEmbeddableDynamicActions: this.initializeDynamicActions.bind(this), }; } @@ -84,12 +86,7 @@ export class EmbeddableEnhancedPlugin uuid: string, getTitle: () => string | undefined, state: DynamicActionsSerializedState - ): { - dynamicActionsApi: HasDynamicActions; - dynamicActionsComparator: StateComparators; - serializeDynamicActions: () => DynamicActionsSerializedState; - startDynamicActions: () => { stopDynamicActions: () => void }; - } { + ): EmbeddableDynamicActionsManager { const dynamicActionsState$ = new BehaviorSubject( getDynamicActionsState(state.enhancements) ); @@ -109,19 +106,21 @@ export class EmbeddableEnhancedPlugin uiActions: this.uiActions!, }); + function getLatestState() { + return { enhancements: dynamicActionsState$.getValue() }; + } + return { - dynamicActionsApi: { ...api, enhancements: { dynamicActions } }, - dynamicActionsComparator: { - enhancements: [ - dynamicActionsState$, - api.setDynamicActions, - (a, b) => { - return deepEqual(getDynamicActionsState(a), getDynamicActionsState(b)); - }, - ], - }, - serializeDynamicActions: () => { - return { enhancements: dynamicActionsState$.getValue() }; + api: { ...api, enhancements: { dynamicActions } }, + comparators: { + enhancements: (a, b) => { + return deepEqual(getDynamicActionsState(a), getDynamicActionsState(b)); + } + } as StateComparators, + latestState$: dynamicActionsState$.pipe(map(() => getLatestState())), + getLatestState, + reinitializeState: (lastState: DynamicActionsSerializedState) => { + api.setDynamicActions(lastState.enhancements); }, startDynamicActions: () => { const stop = this.startDynamicActions(dynamicActions); diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx index 5f1ce2bce0ddd..42eb610292864 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx @@ -84,12 +84,12 @@ export const mapEmbeddableFactory: EmbeddableFactory const controlledBy = getControlledBy(uuid); const titleManager = initializeTitleManager(mapSerializedState); const timeRangeManager = initializeTimeRangeManager(mapSerializedState); - const dynamicActionsApi = getEmbeddableEnhanced()?.initializeReactEmbeddableDynamicActions( + const dynamicActionsManager = getEmbeddableEnhanced()?.initializeEmbeddableDynamicActions( uuid, () => titleManager.api.title$.getValue(), mapSerializedState ); - const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); + const maybeStopDynamicActions = dynamicActionsManager?.startDynamicActions(); const defaultTitle$ = new BehaviorSubject(savedMap.getAttributes().title); const defaultDescription$ = new BehaviorSubject( @@ -111,19 +111,19 @@ export const mapEmbeddableFactory: EmbeddableFactory uuid, }); - function getState() { + function getLatestState() { return { ...mapSerializedState, ...timeRangeManager.getLatestState(), ...titleManager.getLatestState(), - ...(dynamicActionsApi?.serializeDynamicActions() ?? {}), + ...(dynamicActionsManager?.getLatestState() ?? {}), ...crossPanelActions.getLatestState(), ...reduxSync.getLatestState(), }; } function serializeState() { - const rawState = getState(); + const rawState = getLatestState(); // by-reference embeddable if (rawState.savedObjectId) { @@ -158,7 +158,7 @@ export const mapEmbeddableFactory: EmbeddableFactory const unsavedChangesApi = initializeUnsavedChanges({ uuid, parentApi, - serializeState: getState, + serializeState: getLatestState, latestRuntimeState$: combineLatest([ crossPanelActions.latestState$, reduxSync.latestState$, @@ -168,6 +168,7 @@ export const mapEmbeddableFactory: EmbeddableFactory getComparators: () => { return { ...crossPanelActionsComparators, + ...(dynamicActionsManager?.comparators ?? {}), ...reduxSyncComparators, ...titleComparators, ...timeRangeComparators, @@ -181,6 +182,7 @@ export const mapEmbeddableFactory: EmbeddableFactory attributes$.next(lastSaved?.attributes); mapSettings$.next(lastSaved?.mapSettings); savedObjectId$.next(lastSaved?.savedObjectId); + dynamicActionsManager?.reinitializeState(lastSaved ?? {}); reduxSync.reinitializeState(lastSaved); titleManager.reinitializeState(lastSaved); }, @@ -191,10 +193,10 @@ export const mapEmbeddableFactory: EmbeddableFactory defaultDescription$, ...unsavedChangesApi, ...timeRangeManager.api, - ...(dynamicActionsApi?.dynamicActionsApi ?? {}), + ...(dynamicActionsManager?.api ?? {}), ...titleManager.api, ...reduxSync.api, - ...initializeEditApi(uuid, getState, parentApi, mapSerializedState.savedObjectId), + ...initializeEditApi(uuid, getLatestState, parentApi, mapSerializedState.savedObjectId), ...initializeLibraryTransforms(savedMap, serializeState), ...initializeDataViews(savedMap.getStore()), serializeState, From 8444ec3af5576381e3421bad51970e1857d2c0b7 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Sat, 5 Apr 2025 13:08:30 -0600 Subject: [PATCH 4/6] set value get latestState$ --- .../embeddable_enhanced/public/plugin.ts | 4 +++- .../initialize_cross_panel_actions.ts | 20 +++++++++------- .../react_embeddable/initialize_redux_sync.ts | 24 +++++++++++-------- .../react_embeddable/map_react_embeddable.tsx | 3 ++- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts b/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts index 2bca05c0a81c2..44ef91d1e3246 100644 --- a/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts +++ b/x-pack/platform/plugins/shared/embeddable_enhanced/public/plugin.ts @@ -117,7 +117,9 @@ export class EmbeddableEnhancedPlugin return deepEqual(getDynamicActionsState(a), getDynamicActionsState(b)); } } as StateComparators, - latestState$: dynamicActionsState$.pipe(map(() => getLatestState())), + latestState$: dynamicActionsState$.pipe( + map(() => getLatestState()) + ), getLatestState, reinitializeState: (lastState: DynamicActionsSerializedState) => { api.setDynamicActions(lastState.enhancements); diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts index 761c8346921b9..751bcb7091f14 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts @@ -9,7 +9,7 @@ import _ from 'lodash'; import { ACTION_GLOBAL_APPLY_FILTER } from '@kbn/unified-search-plugin/public'; import { i18n } from '@kbn/i18n'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import { BehaviorSubject, combineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest, map } from 'rxjs'; import { getTitle, StateComparators } from '@kbn/presentation-publishing'; import { createExtentFilter } from '../../common/elasticsearch_util'; import { SavedMap } from '../routes/map_page'; @@ -215,22 +215,26 @@ export function initializeCrossPanelActions({ } }); + function getLatestState() { + return { + isMovementSynchronized: isMovementSynchronized$.value, + filterByMapExtent: isFilterByMapExtent$.value, + }; + } + return { cleanup: () => { mapEmbeddablesSingleton.unregister(uuid); unsubscribeFromStore(); }, getIsFilterByMapExtent, - latestState$: combineLatest([isMovementSynchronized$, isFilterByMapExtent$]), + latestState$: combineLatest([isMovementSynchronized$, isFilterByMapExtent$]).pipe( + map(() => getLatestState()) + ), reinitializeState: (lastSaved: MapSerializedState) => { setIsMovementSynchronized(lastSaved.isMovementSynchronized); setIsFilterByMapExtent(lastSaved.filterByMapExtent); }, - getLatestState: () => { - return { - isMovementSynchronized: isMovementSynchronized$.value, - filterByMapExtent: isFilterByMapExtent$.value, - }; - }, + getLatestState, }; } diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts index d5e6d0d6ae4ad..397b111312517 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts @@ -186,6 +186,16 @@ export function initializeReduxSync({ }); } + function getLatestState() { + return { + hiddenLayers: getHiddenLayerIds(store.getState()), + isLayerTOCOpen: getIsLayerTOCOpen(store.getState()), + mapBuffer: getMapBuffer(store.getState()), + mapCenter: getMapCenterAndZoom(store.getState()), + openTOCDetails: getOpenTOCDetails(store.getState()), + }; + } + return { cleanup: () => { if (syncColorsSubscription) syncColorsSubscription.unsubscribe(); @@ -226,22 +236,16 @@ export function initializeReduxSync({ isLayerTOCOpen$, mapCenterAndZoom$, openTOCDetails$, - ]), + ]).pipe( + map(() => getLatestState()) + ), reinitializeState: (lastSaved?: MapSerializedState) => { store.dispatch(setHiddenLayers(lastSaved?.hiddenLayers ?? [])); store.dispatch(setIsLayerTOCOpen(lastSaved?.isLayerTOCOpen ?? true)); if (lastSaved?.mapCenter) store.dispatch(setGotoWithCenter(lastSaved.mapCenter)); store.dispatch(setOpenTOCDetails(lastSaved?.openTOCDetails)); }, - getLatestState: () => { - return { - hiddenLayers: getHiddenLayerIds(store.getState()), - isLayerTOCOpen: getIsLayerTOCOpen(store.getState()), - mapBuffer: getMapBuffer(store.getState()), - mapCenter: getMapCenterAndZoom(store.getState()), - openTOCDetails: getOpenTOCDetails(store.getState()), - }; - }, + getLatestState, }; } diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx index 42eb610292864..b2efc06eae4d1 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx @@ -19,7 +19,7 @@ import { titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { BehaviorSubject, combineLatest } from 'rxjs'; +import { BehaviorSubject, combineLatest, skip } from 'rxjs'; import { apiPublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; import { initializeUnsavedChanges } from '@kbn/presentation-containers'; import { timeRangeComparators } from '@kbn/presentation-publishing/interfaces/fetch/time_range_manager'; @@ -160,6 +160,7 @@ export const mapEmbeddableFactory: EmbeddableFactory parentApi, serializeState: getLatestState, latestRuntimeState$: combineLatest([ + ...(dynamicActionsManager ? [dynamicActionsManager.latestState$] : []), crossPanelActions.latestState$, reduxSync.latestState$, titleManager.latestState$, From 74b34bfb9f83df0cc6a97bed160a022d209b2f6d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Sat, 5 Apr 2025 13:47:45 -0600 Subject: [PATCH 5/6] fix comparators --- .../public/react_embeddable/initialize_redux_sync.ts | 12 +++++------- .../public/react_embeddable/map_react_embeddable.tsx | 5 ++--- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts index 397b111312517..4fddd4f8107b3 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_redux_sync.ts @@ -188,11 +188,11 @@ export function initializeReduxSync({ function getLatestState() { return { - hiddenLayers: getHiddenLayerIds(store.getState()), - isLayerTOCOpen: getIsLayerTOCOpen(store.getState()), + hiddenLayers: hiddenLayers$.value, + isLayerTOCOpen: isLayerTOCOpen$.value, mapBuffer: getMapBuffer(store.getState()), - mapCenter: getMapCenterAndZoom(store.getState()), - openTOCDetails: getOpenTOCDetails(store.getState()), + mapCenter: mapCenterAndZoom$.value, + openTOCDetails: openTOCDetails$.value, }; } @@ -236,9 +236,7 @@ export function initializeReduxSync({ isLayerTOCOpen$, mapCenterAndZoom$, openTOCDetails$, - ]).pipe( - map(() => getLatestState()) - ), + ]).pipe(map(() => getLatestState())), reinitializeState: (lastSaved?: MapSerializedState) => { store.dispatch(setHiddenLayers(lastSaved?.hiddenLayers ?? [])); store.dispatch(setIsLayerTOCOpen(lastSaved?.isLayerTOCOpen ?? true)); diff --git a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx index b2efc06eae4d1..b939cc82c16e7 100644 --- a/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx +++ b/x-pack/platform/plugins/shared/maps/public/react_embeddable/map_react_embeddable.tsx @@ -19,7 +19,7 @@ import { titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { BehaviorSubject, combineLatest, skip } from 'rxjs'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { apiPublishesSettings } from '@kbn/presentation-containers/interfaces/publishes_settings'; import { initializeUnsavedChanges } from '@kbn/presentation-containers'; import { timeRangeComparators } from '@kbn/presentation-publishing/interfaces/fetch/time_range_manager'; @@ -169,12 +169,11 @@ export const mapEmbeddableFactory: EmbeddableFactory getComparators: () => { return { ...crossPanelActionsComparators, - ...(dynamicActionsManager?.comparators ?? {}), + ...(dynamicActionsManager?.comparators ?? { enhancements: 'skip' }), ...reduxSyncComparators, ...titleComparators, ...timeRangeComparators, attributes: 'referenceEquality', - enhancements: 'skip', mapSettings: 'referenceEquality', savedObjectId: 'referenceEquality', }; From 20a8cfa6e542fe7d7d59c3b32c19113cf3e21224 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Mon, 7 Apr 2025 08:42:33 -0600 Subject: [PATCH 6/6] remove debugger --- .../eui_markdown/eui_markdown_react_embeddable.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx index 1ffceb3d34511..2f68f46892893 100644 --- a/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/eui_markdown/eui_markdown_react_embeddable.tsx @@ -73,7 +73,6 @@ export const markdownEmbeddableFactory: EmbeddableFactory< return { ...titleComparators, ...markdownComparators }; }, onReset: (lastSaved) => { - debugger; /** * if this embeddable had a difference between its runtime and serialized state, we could run the 'deserializeState' * function here before resetting. onReset can be async so to support a potential async deserialize function.