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..44ef91d1e3246 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,23 @@ 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/initialize_cross_panel_actions.ts b/x-pack/platform/plugins/shared/maps/public/react_embeddable/initialize_cross_panel_actions.ts index 69a304dd40501..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 } 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'; @@ -30,6 +30,13 @@ import { getGeoFieldsLabel } from './get_geo_fields_label'; import { MapApi, MapSerializedState } from './types'; import { setOnMapMove } from '../reducers/non_serializable_instances'; +export const crossPanelActionsComparators: StateComparators< + Pick +> = { + isMovementSynchronized: 'referenceEquality', + filterByMapExtent: 'referenceEquality', +}; + export function initializeCrossPanelActions({ controlledBy, getActionContext, @@ -51,7 +58,7 @@ export function initializeCrossPanelActions({ function getIsMovementSynchronized() { return isMovementSynchronized$.value ?? true; } - function setIsMovementSynchronized(next: boolean) { + function setIsMovementSynchronized(next: boolean | undefined) { isMovementSynchronized$.next(next); } @@ -59,7 +66,7 @@ export function initializeCrossPanelActions({ function getIsFilterByMapExtent() { return isFilterByMapExtent$.value ?? false; } - function setIsFilterByMapExtent(next: boolean) { + function setIsFilterByMapExtent(next: boolean | undefined) { isFilterByMapExtent$.next(next); } @@ -208,21 +215,26 @@ export function initializeCrossPanelActions({ } }); + function getLatestState() { + return { + isMovementSynchronized: isMovementSynchronized$.value, + filterByMapExtent: isFilterByMapExtent$.value, + }; + } + return { cleanup: () => { mapEmbeddablesSingleton.unregister(uuid); unsubscribeFromStore(); }, - comparators: { - isMovementSynchronized: [isMovementSynchronized$, setIsMovementSynchronized], - filterByMapExtent: [isFilterByMapExtent$, setIsFilterByMapExtent], - } as StateComparators>, getIsFilterByMapExtent, - serialize: () => { - return { - isMovementSynchronized: isMovementSynchronized$.value, - filterByMapExtent: isFilterByMapExtent$.value, - }; + latestState$: combineLatest([isMovementSynchronized$, isFilterByMapExtent$]).pipe( + map(() => getLatestState()) + ), + reinitializeState: (lastSaved: MapSerializedState) => { + setIsMovementSynchronized(lastSaved.isMovementSynchronized); + setIsFilterByMapExtent(lastSaved.filterByMapExtent); }, + 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 cd4117745a4ad..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 @@ -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,28 @@ function getHiddenLayerIds(state: MapStoreState) { .map((layer) => layer.id); } +export const reduxSyncComparators: StateComparators< + Pick< + MapSerializedState, + 'hiddenLayers' | 'isLayerTOCOpen' | 'mapCenter' | 'mapBuffer' | 'openTOCDetails' + > +> = { + 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, @@ -164,6 +186,16 @@ export function initializeReduxSync({ }); } + function getLatestState() { + return { + hiddenLayers: hiddenLayers$.value, + isLayerTOCOpen: isLayerTOCOpen$.value, + mapBuffer: getMapBuffer(store.getState()), + mapCenter: mapCenterAndZoom$.value, + openTOCDetails: openTOCDetails$.value, + }; + } + return { cleanup: () => { if (syncColorsSubscription) syncColorsSubscription.unsubscribe(); @@ -199,56 +231,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: () => { - return { - hiddenLayers: getHiddenLayerIds(store.getState()), - isLayerTOCOpen: getIsLayerTOCOpen(store.getState()), - mapBuffer: getMapBuffer(store.getState()), - mapCenter: getMapCenterAndZoom(store.getState()), - openTOCDetails: getOpenTOCDetails(store.getState()), - }; + latestState$: combineLatest([ + hiddenLayers$, + 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, }; } 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..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 @@ -9,23 +9,25 @@ 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 { 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 { 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, 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 +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 { 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'; @@ -48,29 +53,27 @@ export function getControlledBy(id: string) { return `mapEmbeddablePanel${id}`; } -export const mapEmbeddableFactory: ReactEmbeddableFactory< - MapSerializedState, - MapRuntimeState, - MapApi -> = { +export const mapEmbeddableFactory: EmbeddableFactory = { type: MAP_SAVED_OBJECT_TYPE, - deserializeState: (state) => { - return state.rawState + buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + const mapSerializedState = initialState.rawState ? (inject( - state.rawState as EmbeddableStateWithType, - state.references ?? [] + initialState.rawState as EmbeddableStateWithType, + initialState.references ?? [] ) as unknown as MapSerializedState) : {}; - }, - buildEmbeddable: async (state, buildApi, uuid, parentApi) => { - const savedMap = new SavedMap({ - mapSerializedState: state, - }); + 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,14 +82,14 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< const sharingSavedObjectProps = savedMap.getSharingSavedObjectProps(); const spaces = getSpacesApi(); const controlledBy = getControlledBy(uuid); - const titleManager = initializeTitleManager(state); - const timeRange = initializeTimeRange(state); - const dynamicActionsApi = getEmbeddableEnhanced()?.initializeReactEmbeddableDynamicActions( + const titleManager = initializeTitleManager(mapSerializedState); + const timeRangeManager = initializeTimeRangeManager(mapSerializedState); + const dynamicActionsManager = getEmbeddableEnhanced()?.initializeEmbeddableDynamicActions( uuid, () => titleManager.api.title$.getValue(), - state + mapSerializedState ); - const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); + const maybeStopDynamicActions = dynamicActionsManager?.startDynamicActions(); const defaultTitle$ = new BehaviorSubject(savedMap.getAttributes().title); const defaultDescription$ = new BehaviorSubject( @@ -94,7 +97,7 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< ); const reduxSync = initializeReduxSync({ savedMap, - state, + state: mapSerializedState, syncColors$: apiPublishesSettings(parentApi) ? parentApi.settings.syncColors$ : undefined, uuid, }); @@ -103,24 +106,24 @@ export const mapEmbeddableFactory: ReactEmbeddableFactory< controlledBy, getActionContext: actionHandlers.getActionContext, getApi, - state, + state: mapSerializedState, savedMap, uuid, }); - function getState() { + function getLatestState() { return { - ...state, - ...timeRange.serialize(), - ...titleManager.serialize(), - ...(dynamicActionsApi?.serializeDynamicActions() ?? {}), - ...crossPanelActions.serialize(), - ...reduxSync.serialize(), + ...mapSerializedState, + ...timeRangeManager.getLatestState(), + ...titleManager.getLatestState(), + ...(dynamicActionsManager?.getLatestState() ?? {}), + ...crossPanelActions.getLatestState(), + ...reduxSync.getLatestState(), }; } function serializeState() { - const rawState = getState(); + const rawState = getLatestState(); // by-reference embeddable if (rawState.savedObjectId) { @@ -152,46 +155,61 @@ 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: getLatestState, + latestRuntimeState$: combineLatest([ + ...(dynamicActionsManager ? [dynamicActionsManager.latestState$] : []), + crossPanelActions.latestState$, + reduxSync.latestState$, + titleManager.latestState$, + timeRangeManager.latestState$, + ]), + getComparators: () => { + return { + ...crossPanelActionsComparators, + ...(dynamicActionsManager?.comparators ?? { enhancements: 'skip' }), + ...reduxSyncComparators, + ...titleComparators, + ...timeRangeComparators, + attributes: 'referenceEquality', + mapSettings: 'referenceEquality', + savedObjectId: 'referenceEquality', + }; + }, + onReset: (lastSaved) => { + attributes$.next(lastSaved?.attributes); + mapSettings$.next(lastSaved?.mapSettings); + savedObjectId$.next(lastSaved?.savedObjectId); + dynamicActionsManager?.reinitializeState(lastSaved ?? {}); + reduxSync.reinitializeState(lastSaved); + titleManager.reinitializeState(lastSaved); + }, + }); + + api = finalizeApi({ + defaultTitle$, + defaultDescription$, + ...unsavedChangesApi, + ...timeRangeManager.api, + ...(dynamicActionsManager?.api ?? {}), + ...titleManager.api, + ...reduxSync.api, + ...initializeEditApi(uuid, getLatestState, 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..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 @@ -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..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,13 +45,10 @@ export type MapSerializedState = SerializedTitles & mapBuffer?: MapExtent; mapSettings?: Partial; hiddenLayers?: string[]; - timeRange?: TimeRange; filterByMapExtent?: boolean; isMovementSynchronized?: boolean; }; -export type MapRuntimeState = MapSerializedState; - export type MapApi = DefaultEmbeddableApi & HasDynamicActions & Partial &