From d8a2bf8de80099e7e324b1152650f4103a609ad8 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Wed, 1 Apr 2026 19:13:52 -0400 Subject: [PATCH 01/10] Update naming of functions to make state ownership clearer. Renamed and changed types for unsaved changes blurp --- .../data_table_react_embeddable.tsx | 16 ++-- .../field_list/field_list_embeddable.tsx | 16 ++-- .../saved_book_react_embeddable.tsx | 20 ++--- .../search/search_react_embeddable.tsx | 18 ++--- .../presentation_publishing/index.ts | 8 +- .../children_unsaved_changes.test.ts | 0 .../children_unsaved_changes.ts | 0 .../link_to_container_state.ts} | 50 +++++++------ .../state_manager/state_manager.ts | 8 +- .../state_manager/types.ts | 6 ++ .../get_image_embeddable_factory.tsx | 38 ++++------ .../public/embeddable/links_embeddable.tsx | 24 +++--- .../get_options_list_control_factory.tsx | 47 ++++++------ .../get_range_slider_control_factory.tsx | 40 +++++----- .../esql_control/get_esql_control_factory.tsx | 36 +++++---- .../get_timeslider_control_factory.tsx | 34 ++++----- .../public/markdown_embeddable.tsx | 19 ++--- .../get_search_embeddable_factory.tsx | 30 ++++---- .../react_embeddable_renderer.tsx | 13 ++-- .../public/react_embeddable_system/types.ts | 9 +++ .../embeddable/visualize_embeddable.tsx | 31 ++++---- .../field_stats/field_stats_factory.tsx | 38 +++++----- .../embeddable_change_point_chart_factory.tsx | 38 +++++----- .../embeddable_log_rate_analysis_factory.tsx | 38 +++++----- .../embeddable_pattern_analysis_factory.tsx | 40 +++++----- .../alerts_table_embeddable_factory.tsx | 32 ++++---- .../react_embeddable/lens_embeddable.tsx | 34 ++++----- .../react_embeddable/map_react_embeddable.tsx | 31 ++++---- .../anomaly_charts_embeddable_factory.tsx | 38 +++++----- .../anomaly_swimlane_embeddable_factory.tsx | 39 +++++----- ...ingle_metric_viewer_embeddable_factory.tsx | 38 +++++----- .../react_embeddable_factory.tsx | 64 +++++++--------- .../react_embeddable_factory.tsx | 68 ++++++++--------- .../react_embeddable_factory.tsx | 64 +++++++--------- .../alerts/slo_alerts_embeddable_factory.tsx | 28 +++---- .../burn_rate_react_embeddable_factory.tsx | 33 +++------ .../error_budget_react_embeddable_factory.tsx | 33 +++------ .../slo/overview/slo_embeddable_factory.tsx | 73 +++++++++---------- .../monitors_embeddable_factory.tsx | 32 +++----- .../stats_overview_embeddable_factory.tsx | 33 +++------ 40 files changed, 561 insertions(+), 696 deletions(-) rename src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/{unsaved_changes => container_state}/children_unsaved_changes.test.ts (100%) rename src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/{unsaved_changes => container_state}/children_unsaved_changes.ts (100%) rename src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/{unsaved_changes/initialize_unsaved_changes.ts => container_state/link_to_container_state.ts} (71%) diff --git a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx index eb45a3db59aaa..9835c23ecb7ca 100644 --- a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx @@ -16,7 +16,6 @@ import { i18n } from '@kbn/i18n'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { - initializeUnsavedChanges, initializeTimeRangeManager, initializeTitleManager, timeRangeComparators, @@ -38,7 +37,7 @@ export const getDataTableFactory = ( services: StartDeps ): EmbeddableFactory => ({ type: DATA_TABLE_ID, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, linkToContainerState, finalizeApi, parentApi, uuid }) => { const state = initialState; const timeRangeManager = initializeTimeRangeManager(state); const dataLoading$ = new BehaviorSubject(true); @@ -60,9 +59,7 @@ export const getDataTableFactory = ( }; }; - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, + const containerLinkApi = linkToContainerState({ serializeState, anyStateChange$: merge(titleManager.anyStateChange$, timeRangeManager.anyStateChange$), getComparators: () => { @@ -71,18 +68,17 @@ export const getDataTableFactory = ( ...timeRangeComparators, }; }, - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); }, }); const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...unsavedChangesApi, + ...containerLinkApi, dataLoading$, - serializeState, }); const queryService = await initializeDataTableQueries(services, api, dataLoading$); diff --git a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx index b94ac8c751fc3..3287334d3bdd9 100644 --- a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx @@ -19,7 +19,6 @@ import { initializeTitleManager, titleComparators, useBatchedPublishingSubjects, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import { LazyDataViewPicker, withSuspense } from '@kbn/presentation-util-plugin/public'; import { @@ -85,7 +84,7 @@ export const getFieldListFactory = ( ) => { const fieldListEmbeddableFactory: EmbeddableFactory = { type: FIELD_LIST_ID, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const state = await deserializeState(dataViews, initialState); const allDataViews = await dataViews.getIdsWithTitle(); const subscriptions = new Subscription(); @@ -117,19 +116,17 @@ export const getFieldListFactory = ( }; } - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge(titleManager.anyStateChange$, fieldListStateManager.anyStateChange$), getComparators: () => ({ ...titleComparators, - selectedFieldNames: (a, b) => { + selectedFieldNames: (a: string[] | undefined, b: string[] | undefined) => { return (a?.slice().sort().join(',') ?? '') === (b?.slice().sort().join(',') ?? ''); }, dataViewId: 'referenceEquality', }), - onReset: async (lastSaved) => { + serializeState, + applySerializedState: async (lastSaved: FieldListSerializedState | undefined) => { const lastState = await deserializeState(dataViews, lastSaved); fieldListStateManager.reinitializeState(lastState); titleManager.reinitializeState(lastSaved); @@ -138,8 +135,7 @@ export const getFieldListFactory = ( const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, - serializeState, + ...containerStateApi, }); return { diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx index 956f3500c378c..599622e50f502 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx @@ -28,7 +28,6 @@ import { initializeStateManager, titleComparators, apiIsPresentationContainer, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import React from 'react'; import { merge } from 'rxjs'; @@ -50,7 +49,7 @@ const bookStateComparators: StateComparators = { export const getSavedBookEmbeddableFactory = (core: CoreStart) => { const savedBookEmbeddableFactory: EmbeddableFactory = { type: BOOK_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const titleManager = initializeTitleManager(initialState); const savedObjectId = (initialState as BookByReferenceState).savedObjectId; const initialBookState = savedObjectId ? await loadBook(savedObjectId) : initialState; @@ -65,12 +64,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { ...(id ? { savedObjectId: id } : bookStateManager.getLatestState()), }); - const serializeState = () => serializeBook(savedObjectId); - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge(titleManager.anyStateChange$, bookStateManager.anyStateChange$), getComparators: () => { return { @@ -79,14 +73,15 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { savedObjectId: 'skip', // saved book id will not change over the lifetime of the embeddable. }; }, - onReset: async (lastSaved) => { - titleManager.reinitializeState(lastSaved); - if (!savedObjectId) bookStateManager.reinitializeState(lastSaved as BookState); + serializeState: () => serializeBook(savedObjectId), + applySerializedState: async (nextState) => { + titleManager.reinitializeState(nextState); + if (!savedObjectId) bookStateManager.reinitializeState(nextState as BookState); }, }); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...titleManager.api, onEdit: async () => { openLazyFlyout({ @@ -122,7 +117,6 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { i18n.translate('embeddableExamples.savedbook.editBook.displayName', { defaultMessage: 'book', }), - serializeState, // library transforms getSavedObjectId: () => savedObjectId, diff --git a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx index 9070a7e78e5da..ff5aec943be07 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx @@ -17,7 +17,6 @@ import { initializeTimeRangeManager, timeRangeComparators, useBatchedPublishingSubjects, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import React, { useEffect } from 'react'; import { BehaviorSubject, switchMap, tap } from 'rxjs'; @@ -28,7 +27,7 @@ import type { SearchApi, Services, SearchSerializedState } from './types'; export const getSearchEmbeddableFactory = (services: Services) => { const factory: EmbeddableFactory = { type: SEARCH_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const timeRangeManager = initializeTimeRangeManager(initialState); const defaultDataView = await services.dataViews.getDefaultDataView(); const dataViews$ = new BehaviorSubject( @@ -53,10 +52,7 @@ export const getSearchEmbeddableFactory = (services: Services) => { }; } - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: timeRangeManager.anyStateChange$, getComparators: () => { /** @@ -66,13 +62,14 @@ export const getSearchEmbeddableFactory = (services: Services) => { */ return timeRangeComparators; }, - onReset: (lastSaved) => { + serializeState, + applySerializedState: (nextState) => { /** * 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. + * function here before applying the state. onReset can be async to support a potential async deserialize function. */ - timeRangeManager.reinitializeState(lastSaved); + timeRangeManager.reinitializeState(nextState); }, }); @@ -80,9 +77,8 @@ export const getSearchEmbeddableFactory = (services: Services) => { blockingError$, dataViews$, dataLoading$, - ...unsavedChangesApi, + ...containerStateApi, ...timeRangeManager.api, - serializeState, }); const count$ = new BehaviorSubject(0); diff --git a/src/platform/packages/shared/presentation/presentation_publishing/index.ts b/src/platform/packages/shared/presentation/presentation_publishing/index.ts index be2ffd667601f..81ca4db6ad710 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/index.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/index.ts @@ -207,9 +207,11 @@ export { type HasSerializedChildState, } from './interfaces/containers/child_state'; -export { childrenUnsavedChanges$ } from './interfaces/containers/unsaved_changes/children_unsaved_changes'; - -export { initializeUnsavedChanges } from './interfaces/containers/unsaved_changes/initialize_unsaved_changes'; +export { childrenUnsavedChanges$ } from './interfaces/containers/container_state/children_unsaved_changes'; +export { + linkToContainerState, + type ContainerStateManagerInitializer, +} from './interfaces/containers/container_state/link_to_container_state'; export { apiCanDuplicatePanels, diff --git a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/children_unsaved_changes.test.ts b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/children_unsaved_changes.test.ts similarity index 100% rename from src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/children_unsaved_changes.test.ts rename to src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/children_unsaved_changes.test.ts diff --git a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/children_unsaved_changes.ts b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/children_unsaved_changes.ts similarity index 100% rename from src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/children_unsaved_changes.ts rename to src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/children_unsaved_changes.ts diff --git a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/initialize_unsaved_changes.ts b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts similarity index 71% rename from src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/initialize_unsaved_changes.ts rename to src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts index c7f65d2f6da10..c016a09e9cb37 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/unsaved_changes/initialize_unsaved_changes.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts @@ -7,42 +7,42 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import type { Observable } from 'rxjs'; -import type { MaybePromise } from '@kbn/utility-types'; import { combineLatestWith, debounceTime, map, of } from 'rxjs'; +import { type StateComparators, areComparatorsEqual } from '../../../state_manager'; +import type { StateManager, StateManagerInitializer } from '../../../state_manager/types'; +import type { HasParentApi } from '../../has_parent_api'; import type { HasSerializableState } from '../../has_serializable_state'; +import type { HasUniqueId } from '../../has_uuid'; import type { PublishesUnsavedChanges } from '../../publishes_unsaved_changes'; -import { type StateComparators, areComparatorsEqual } from '../../../state_manager'; import { getTitle } from '../../titles/publishes_title'; import { apiHasLastSavedChildState } from '../last_saved_child_state'; import type { PresentationContainer } from '../presentation_container'; + const UNSAVED_CHANGES_DEBOUNCE = 100; -export const initializeUnsavedChanges = ({ +export interface ContainerStateManagerInitializer + extends HasSerializableState { + defaultState?: StateManagerInitializer['defaultState']; + anyStateChange$: StateManager['anyStateChange$']; + getComparators: () => StateComparators; +} + +export const linkToContainerState = ({ uuid, - onReset, parentApi, - getComparators, defaultState, - serializeState, anyStateChange$, - checkRefEquality, -}: { - uuid: string; - parentApi: unknown; - anyStateChange$: Observable; - serializeState: () => StateType; - getComparators: () => StateComparators; - defaultState?: Partial; - onReset?: (lastSavedPanelState?: StateType) => MaybePromise; - checkRefEquality?: boolean; -}): PublishesUnsavedChanges & Pick, 'applySerializedState'> => { - const applySerializedState = async (state?: StateType) => { - await onReset?.(state); - }; - + serializeState, + getComparators, + applySerializedState, +}: HasSerializableState & + HasUniqueId & + HasParentApi & + ContainerStateManagerInitializer): PublishesUnsavedChanges & + HasSerializableState => { if (!apiHasLastSavedChildState(parentApi)) { return { + serializeState, applySerializedState, hasUnsavedChanges$: of(false), }; @@ -72,5 +72,9 @@ export const initializeUnsavedChanges = ({ }) ); - return { applySerializedState, hasUnsavedChanges$ }; + return { + serializeState, + hasUnsavedChanges$, + applySerializedState, + }; }; diff --git a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/state_manager.ts b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/state_manager.ts index 9fac069655c11..15d00a3cab90f 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/state_manager.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/state_manager.ts @@ -10,7 +10,7 @@ import { camelCase } from 'lodash'; import { BehaviorSubject, map, merge } from 'rxjs'; import { runComparator } from './state_comparators'; -import type { StateComparators, StateManager, WithAllKeys } from './types'; +import type { StateManager, StateManagerInitializer, WithAllKeys } from './types'; type SubjectOf = BehaviorSubject[keyof StateType]>; @@ -29,9 +29,9 @@ type KeyToSubjectMap = { * @param comparators - Optional StateComparators. When provided, subject will only emit when value changes. */ export const initializeStateManager = ( - initialState: Partial, - defaultState: WithAllKeys, - comparators?: StateComparators + initialState: StateManagerInitializer['initialState'], + defaultState: StateManagerInitializer['defaultState'], + comparators?: StateManagerInitializer['comparators'] ): StateManager => { const allState = { ...defaultState, ...initialState }; const allSubjects: Array> = []; diff --git a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/types.ts b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/types.ts index 45f8cda4fa7c9..445466518793b 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/types.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/types.ts @@ -13,6 +13,12 @@ import type { SnakeToCamelCase } from '../utils/types'; export type WithAllKeys = { [Key in keyof Required]: T[Key] }; +export interface StateManagerInitializer { + initialState: Partial; + defaultState: WithAllKeys; + comparators?: StateComparators; +} + export type ComparatorFunction = ( last: StateType[KeyType] | undefined, current: StateType[KeyType] | undefined, diff --git a/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx b/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx index a38782a52c584..d08702968de5b 100644 --- a/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx +++ b/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx @@ -13,11 +13,7 @@ import { BehaviorSubject, map, merge } from 'rxjs'; import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { openLazyFlyout } from '@kbn/presentation-util'; -import { - initializeUnsavedChanges, - initializeTitleManager, - titleComparators, -} from '@kbn/presentation-publishing'; +import { initializeTitleManager, titleComparators } from '@kbn/presentation-publishing'; import type { ImageEmbeddableState } from '../../server'; import { ImageEmbeddable as ImageEmbeddableComponent } from '../components/image_embeddable'; @@ -31,10 +27,11 @@ export const getImageEmbeddableFactory = () => { type: IMAGE_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, + linkToContainerState, initialState, finalizeApi, - uuid, parentApi, + uuid, }) => { const titleManager = initializeTitleManager(initialState); @@ -44,18 +41,7 @@ export const getImageEmbeddableFactory = () => { const imageConfig$ = new BehaviorSubject(initialState.image_config); const dataLoading$ = new BehaviorSubject(true); - function serializeState() { - return { - ...titleManager.getLatestState(), - ...drilldownsManager.getLatestState(), - image_config: imageConfig$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, imageConfig$.pipe(map(() => undefined)), @@ -68,17 +54,22 @@ export const getImageEmbeddableFactory = () => { image_config: 'deepEquality', }; }, - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - drilldownsManager.reinitializeState(lastSaved ?? {}); - if (lastSaved) imageConfig$.next(lastSaved.image_config); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...drilldownsManager.getLatestState(), + image_config: imageConfig$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + drilldownsManager.reinitializeState(nextState ?? {}); + if (nextState) imageConfig$.next(nextState.image_config); }, }); const embeddable = finalizeApi({ ...titleManager.api, ...drilldownsManager.api, - ...unsavedChangesApi, + ...containerStateApi, dataLoading$, supportedTriggers: () => IMAGE_EMBEDDABLE_SUPPORTED_TRIGGERS, @@ -106,7 +97,6 @@ export const getImageEmbeddableFactory = () => { i18n.translate('imageEmbeddable.imageEmbeddableFactory.displayName.edit', { defaultMessage: 'image', }), - serializeState, }); return { api: embeddable, diff --git a/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx b/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx index 1c1b04ce060fc..217bcbf10824a 100644 --- a/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx +++ b/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx @@ -22,7 +22,6 @@ import { useBatchedPublishingSubjects, titleComparators, apiIsPresentationContainer, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import { css } from '@emotion/react'; import { openLazyFlyout } from '@kbn/presentation-util'; @@ -49,7 +48,7 @@ export const LinksContext = createContext(null); export const getLinksEmbeddableFactory = () => { const linksEmbeddableFactory: EmbeddableFactory = { type: LINKS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, parentApi }) => { const savedObjectId = (initialState as LinksByReferenceState).savedObjectId; const intialLinksState = savedObjectId ? await loadFromLibrary(savedObjectId) @@ -86,13 +85,7 @@ export const getLinksEmbeddableFactory = () => { }; } - const serializeState = () => - isByReference ? serializeByReference(savedObjectId) : serializeByValue(); - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, layout$.pipe(map(() => undefined)), @@ -121,24 +114,25 @@ export const getLinksEmbeddableFactory = () => { savedObjectId: 'skip', }; }, - onReset: async (lastSaved) => { - titleManager.reinitializeState(lastSaved); + serializeState: () => + isByReference ? serializeByReference(savedObjectId) : serializeByValue(), + applySerializedState: async (nextState) => { + titleManager.reinitializeState(nextState); if (!savedObjectId) { - layout$.next((lastSaved as LinksByValueState)?.layout); - resolvedLinks$.next(await resolveLinks((lastSaved as LinksByValueState)?.links ?? [])); + layout$.next((nextState as LinksByValueState)?.layout); + resolvedLinks$.next(await resolveLinks((nextState as LinksByValueState)?.links ?? [])); } }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, blockingError$, defaultTitle$, defaultDescription$, isEditingEnabled: () => Boolean(blockingError$.value === undefined), getTypeDisplayName: () => DISPLAY_NAME, - serializeState, saveToLibrary: async (newTitle: string) => { defaultTitle$.next(newTitle); const { diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx index aac114c8e9611..05f119cc7716b 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx @@ -27,7 +27,6 @@ import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { apiHasPinnedPanels, apiHasSections, - initializeUnsavedChanges, type PublishingSubject, } from '@kbn/presentation-publishing'; @@ -66,7 +65,13 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< > => { return { type: OPTIONS_LIST_CONTROL, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const state = initialState; if (isOptionsListESQLControlState(state)) { @@ -149,7 +154,6 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< loadMoreSubject, loadingSuggestions$, debouncedSearchString, - parentApi, uuid, }, requestSize$: temporaryStateManager.api.requestSize$, @@ -235,21 +239,7 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< } ); - function serializeState(): OptionsListControlState { - return { - ...dataControlManager.getLatestState(), - ...selectionsManager.getLatestState(), - ...editorStateManager.getLatestState(), - - // serialize state that cannot be changed to keep it consistent - display_settings: state.display_settings, - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( dataControlManager.anyStateChange$, selectionsManager.anyStateChange$, @@ -270,13 +260,21 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< exclude: false, exists_selected: false, }, - onReset: (lastSaved) => { - if (isOptionsListESQLControlState(lastSaved)) { + serializeState: () => ({ + ...dataControlManager.getLatestState(), + ...selectionsManager.getLatestState(), + ...editorStateManager.getLatestState(), + + // serialize state that cannot be changed to keep it consistent + display_settings: state.display_settings, + }), + applySerializedState: (nextState) => { + if (isOptionsListESQLControlState(nextState)) { throw new Error('ES|QL control state handling not yet implemented'); } - dataControlManager.reinitializeState(lastSaved); - selectionsManager.reinitializeState(lastSaved); - editorStateManager.reinitializeState(lastSaved); + dataControlManager.reinitializeState(nextState); + selectionsManager.reinitializeState(nextState); + editorStateManager.reinitializeState(nextState); }, }); @@ -293,12 +291,11 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< .subscribe((error) => blockingError$.next(error)); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...dataControlManager.api, blockingError$, dataLoading$: temporaryStateManager.api.dataLoading$, getTypeDisplayName: OptionsListStrings.control.getDisplayName, - serializeState, clearSelections: () => clearSelections({ selectionsManager, temporaryStateManager }), hasSelections$: hasSelections$ as PublishingSubject, setSelectedOptions: selectionsManager.api.setSelectedOptions, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx index 4d13f2745f06c..601c44715011d 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx @@ -15,7 +15,6 @@ import { apiHasSections, apiPublishesViewMode, fetch$, - initializeUnsavedChanges, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; import { DEFAULT_RANGE_SLIDER_STATE, RANGE_SLIDER_CONTROL } from '@kbn/controls-constants'; @@ -42,7 +41,13 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< > => { return { type: RANGE_SLIDER_CONTROL, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const state = initialState; const loadingMinMax$ = new BehaviorSubject(false); const loadingHasNoResults$ = new BehaviorSubject(false); @@ -68,18 +73,7 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< dataControlManager.internalApi.onSelectionChange ); - function serializeState() { - return { - ...dataControlManager.getLatestState(), - ...editorStateManager.getLatestState(), - value: selections.value$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( dataControlManager.anyStateChange$, selections.value$, @@ -92,18 +86,22 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< value: 'deepEquality', }; }, - onReset: (lastSaved) => { - dataControlManager.reinitializeState(lastSaved); - editorStateManager.reinitializeState(lastSaved); - selections.setValue(lastSaved?.value); + serializeState: () => ({ + ...dataControlManager.getLatestState(), + ...editorStateManager.getLatestState(), + value: selections.value$.getValue(), + }), + applySerializedState: (nextState) => { + dataControlManager.reinitializeState(nextState); + editorStateManager.reinitializeState(nextState); + selections.setValue(nextState?.value); }, }); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...dataControlManager.api, dataLoading$, - serializeState, clearSelections: () => { selections.setValue(undefined); }, @@ -134,7 +132,7 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< selections.setValue(undefined); }); - const controlFetch$ = fetch$({ uuid, parentApi }); + const controlFetch$ = fetch$({ parentApi }); const max$ = new BehaviorSubject(undefined); const min$ = new BehaviorSubject(undefined); const minMaxSubscription = minMax$({ diff --git a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx index e6efadc6aa0cb..c756ac96bc10a 100644 --- a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx @@ -14,7 +14,7 @@ import { pick } from 'lodash'; import { ESQL_CONTROL } from '@kbn/controls-constants'; import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { apiPublishesESQLVariables } from '@kbn/esql-types'; -import { apiHasPinnedPanels, initializeUnsavedChanges } from '@kbn/presentation-publishing'; +import { apiHasPinnedPanels } from '@kbn/presentation-publishing'; import type { OptionsListESQLControlState } from '@kbn/controls-schemas'; import { uiActionsService } from '../../services/kibana_services'; @@ -31,7 +31,13 @@ export const getESQLControlFactory = (): EmbeddableFactory< > => { return { type: ESQL_CONTROL, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + uuid, + parentApi, + finalizeApi, + initialState, + linkToContainerState, + }) => { const state = initialState; const dataLoading$ = new BehaviorSubject(false); @@ -43,18 +49,7 @@ export const getESQLControlFactory = (): EmbeddableFactory< selections.internalApi, 'variableName' ); - - function serializeState() { - return { - ...selections.getLatestState(), - ...labelManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: selections.anyStateChange$, getComparators: () => { return { @@ -63,14 +58,18 @@ export const getESQLControlFactory = (): EmbeddableFactory< display_settings: 'skip', }; }, - onReset: (lastSaved) => { - selections.reinitializeState(lastSaved); - labelManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...selections.getLatestState(), + ...labelManager.getLatestState(), + }), + applySerializedState: (nextState) => { + selections.reinitializeState(nextState); + labelManager.reinitializeState(nextState); }, }); const api: ESQLControlApi = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...selections.api, ...labelManager.api, dataLoading$, @@ -115,7 +114,6 @@ export const getESQLControlFactory = (): EmbeddableFactory< console.error('Error getting ESQL control trigger', e); } }, - serializeState, }); const componentApi: ESQLOptionsListComponentApi = { diff --git a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx index 345cbbd1c36f8..cb790c0b9fd85 100644 --- a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx @@ -18,7 +18,6 @@ import { getViewModeSubject, useBatchedPublishingSubjects, apiPublishesSettings, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import { DEFAULT_TIME_SLIDER_STATE, TIME_SLIDER_CONTROL } from '@kbn/controls-constants'; @@ -53,7 +52,13 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< > => { return { type: TIME_SLIDER_CONTROL, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const state = initialState; const { timeRangeMeta$, formatDate, cleanupTimeRangeSubscription } = @@ -223,17 +228,7 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< }) ); - function serializeState() { - return { - ...timeRangePercentage.getLatestState(), - is_anchored: isAnchored$.value, - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( timeRangePercentage.anyStateChange$, isAnchored$.pipe(map(() => undefined)) @@ -245,18 +240,21 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< is_anchored: 'referenceEquality', }; }, - onReset: (lastSaved) => { - timeRangePercentage.reinitializeState(lastSaved); - setIsAnchored(lastSaved?.is_anchored ?? DEFAULT_TIME_SLIDER_STATE.is_anchored); + serializeState: () => ({ + ...timeRangePercentage.getLatestState(), + is_anchored: isAnchored$.value, + }), + applySerializedState: (nextState) => { + timeRangePercentage.reinitializeState(nextState); + setIsAnchored(nextState?.is_anchored ?? DEFAULT_TIME_SLIDER_STATE.is_anchored); }, }); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, isPinnable: false, // Disable the user-facing unpin action; panel can still be pinned programatically when it's created label$: new BehaviorSubject(displayName), appliedTimeslice$: timeslice$, - serializeState, clearSelections: () => { setTimeslice(undefined); hasTimeSliceSelection$.next(false); diff --git a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx index 099671c25506f..928aeb0d611f5 100644 --- a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx +++ b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx @@ -14,7 +14,6 @@ import { apiCanAddNewPanel, apiCanFocusPanel, apiIsPresentationContainer, - initializeUnsavedChanges, getViewModeSubject, initializeTitleManager, titleComparators, @@ -48,7 +47,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< MarkdownEditorApi > = { type: MARKDOWN_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, parentApi }) => { const libraryId = (initialState as MarkdownByReferenceState).ref_id; const isByReference = libraryId !== undefined; const initialLibraryState = isByReference @@ -87,9 +86,6 @@ export const markdownEmbeddableFactory: EmbeddableFactory< }; }; - const serializeState = () => - isByReference ? serializeByReference(libraryId) : serializeByValue(); - const resetEditingState = () => { isEditing$.next(false); overrideHoverActions$.next(false); @@ -99,10 +95,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< } }; - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, content$.pipe(map(() => undefined)) @@ -114,8 +107,9 @@ export const markdownEmbeddableFactory: EmbeddableFactory< ref_id: 'skip', }; }, - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); + serializeState: () => (isByReference ? serializeByReference(libraryId) : serializeByValue()), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); // There are no unsaved changes to reset for // by reference 'content' since by reference 'content' is saved on apply. if (!isByReference) { @@ -125,11 +119,10 @@ export const markdownEmbeddableFactory: EmbeddableFactory< }); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...titleManager.api, defaultTitle$, defaultDescription$, - serializeState, onEdit: async ({ isNewPanel = false } = {}) => { if (!apiCanAddNewPanel(parentApi)) throw new IncompatibleActionError(); isEditing$.next(true); diff --git a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx index 246cd1747de14..5a3196db79c38 100644 --- a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx +++ b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx @@ -23,7 +23,6 @@ import { timeRangeComparators, titleComparators, useBatchedPublishingSubjects, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { SearchResponseIncompleteWarning } from '@kbn/search-response-warnings/src/types'; @@ -66,6 +65,7 @@ export const getSearchEmbeddableFactory = ({ type: SEARCH_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, + linkToContainerState, initialState, finalizeApi, parentApi, @@ -131,18 +131,15 @@ export const getSearchEmbeddableFactory = ({ const inlineEditingApi = initializeInlineEditingApi({ uuid, - parentApi, tabs, + parentApi, + dataLoading$, selectedTabId$, - searchEmbeddable, blockingError$, - dataLoading$, + searchEmbeddable, }); - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState: () => serialize(savedObjectId$.getValue()), + const containerStateApi = linkToContainerState({ anyStateChange$: merge( drilldownsManager.anyStateChange$, searchEmbeddable.anyStateChange$, @@ -190,13 +187,14 @@ export const getSearchEmbeddableFactory = ({ tabs: 'skip', }; }, - onReset: async (lastSaved) => { - drilldownsManager.reinitializeState(lastSaved ?? {}); - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) { + serializeState: () => serialize(savedObjectId$.getValue()), + applySerializedState: async (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) { const lastSavedRuntimeState = await deserializeState({ - serializedState: lastSaved, + serializedState: nextState, discoverServices, }); @@ -212,7 +210,6 @@ export const getSearchEmbeddableFactory = ({ const editApi = initializeEditApi({ uuid, - parentApi, partialApi: { ...searchEmbeddable.api, fetchContext$, savedObjectId$, getSelectedTabId }, discoverServices, isEditable: startServices.isEditable, @@ -220,7 +217,7 @@ export const getSearchEmbeddableFactory = ({ }); const api: SearchEmbeddableApi = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...titleManager.api, ...searchEmbeddable.api, ...timeRangeManager.api, @@ -276,7 +273,6 @@ export const getSearchEmbeddableFactory = ({ }), getSerializedStateByValue: () => serialize(undefined), getSerializedStateByReference: (newId: string) => serialize(newId), - serializeState: () => serialize(savedObjectId$.getValue()), getInspectorAdapters: () => searchEmbeddable.stateManager.inspectorAdapters.getValue(), supportedTriggers: () => { return [ON_OPEN_PANEL_MENU]; diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index 10c85acdf00d5..22825ce16c416 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -7,19 +7,17 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; +import { PresentationPanel } from '@kbn/presentation-panel-plugin/public'; +import type { HasPanelCapabilities, HasSerializedChildState } from '@kbn/presentation-publishing'; +import { apiIsPresentationContainer, linkToContainerState } from '@kbn/presentation-publishing'; import React, { useImperativeHandle, useMemo, useRef } from 'react'; import { BehaviorSubject } from 'rxjs'; import { v4 as generateId } from 'uuid'; - -import type { HasPanelCapabilities, HasSerializedChildState } from '@kbn/presentation-publishing'; -import { apiIsPresentationContainer } from '@kbn/presentation-publishing'; -import type { PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; -import { PresentationPanel } from '@kbn/presentation-panel-plugin/public'; - +import type { SerializedDrilldowns } from '../../server'; import { PhaseTracker } from './phase_tracker'; import { getReactEmbeddableFactory } from './react_embeddable_registry'; import type { DefaultEmbeddableApi, EmbeddableApiRegistration } from './types'; -import type { SerializedDrilldowns } from '../../server'; /** * Renders a component from the React Embeddable registry into a Presentation Panel. @@ -101,6 +99,7 @@ export const EmbeddableRenderer = < finalizeApi, uuid, parentApi, + linkToContainerState: (args) => linkToContainerState({ ...args, uuid, parentApi }), initializeDrilldownsManager: async ( embeddableUuid: string, state: SerializedDrilldowns diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts index fa81d86b737cd..1ee2564893213 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts @@ -13,6 +13,8 @@ import type { HasSerializableState, HasType, PublishesPhaseEvents, + PublishesUnsavedChanges, + ContainerStateManagerInitializer, } from '@kbn/presentation-publishing'; import type React from 'react'; import type { initializeDrilldownsManager } from '../drilldowns/drilldowns_manager'; @@ -62,6 +64,13 @@ export interface BuildEmbeddableProps< */ parentApi: unknown | undefined; + /** + * Initializes and returns all APIs required for the parent to interact with the state of this API. + */ + linkToContainerState: ( + args: ContainerStateManagerInitializer + ) => PublishesUnsavedChanges & HasSerializableState; + /** * */ diff --git a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx index bbfd26651b70a..28c7087e85296 100644 --- a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx @@ -15,7 +15,7 @@ import type { ExpressionRendererParams } from '@kbn/expressions-plugin/public'; import { useExpressionRenderer } from '@kbn/expressions-plugin/public'; import { i18n } from '@kbn/i18n'; import { dispatchRenderComplete } from '@kbn/kibana-utils-plugin/public'; -import { apiPublishesSettings, initializeUnsavedChanges } from '@kbn/presentation-publishing'; +import { apiPublishesSettings } from '@kbn/presentation-publishing'; import { apiHasDisableTriggers, apiHasExecutionContext, @@ -63,6 +63,7 @@ export const getVisualizeEmbeddableFactory: (deps: { type: VISUALIZE_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, + linkToContainerState, initialState, finalizeApi, parentApi, @@ -189,12 +190,7 @@ export const getVisualizeEmbeddableFactory: (deps: { }); }; - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState: () => { - return serializeVisualizeEmbeddable(savedObjectId$.getValue(), linkedToLibrary); - }, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( drilldownsManager.anyStateChange$, savedObjectId$, @@ -234,14 +230,17 @@ export const getVisualizeEmbeddableFactory: (deps: { }, }; }, - onReset: async (lastSaved) => { - drilldownsManager.reinitializeState(lastSaved ?? {}); - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - - if (!lastSaved) return; - const lastSavedRuntimeState = await deserializeState(lastSaved); - serializedVis$.next(lastSavedRuntimeState.serializedVis); + serializeState: () => { + return serializeVisualizeEmbeddable(savedObjectId$.getValue(), linkedToLibrary); + }, + applySerializedState: async (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + + if (!nextState) return; + const nextRuntimeState = await deserializeState(nextState); + serializedVis$.next(nextRuntimeState.serializedVis); }, }); @@ -249,7 +248,7 @@ export const getVisualizeEmbeddableFactory: (deps: { ...timeRangeManager.api, ...titleManager.api, ...drilldownsManager.api, - ...unsavedChangesApi, + ...containerStateApi, defaultTitle$, dataLoading$, dataViews$: new BehaviorSubject(initialDataViews), diff --git a/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx b/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx index 7343db8a86b1e..66fb41ffb92b7 100644 --- a/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx +++ b/x-pack/platform/plugins/private/data_visualizer/public/application/index_data_visualizer/embeddables/field_stats/field_stats_factory.tsx @@ -20,7 +20,6 @@ import { titleComparators, timeRangeComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import React, { useEffect } from 'react'; import useObservable from 'react-use/lib/useObservable'; import { @@ -109,7 +108,13 @@ export const getFieldStatsChartEmbeddableFactory = ( FieldStatisticsTableEmbeddableApi > = { type: FIELD_STATS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ uuid, initialState, parentApi, finalizeApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const [coreStart, pluginStart] = await getStartServices(); const { http, uiSettings, notifications, ...startServices } = coreStart; @@ -191,18 +196,7 @@ export const getFieldStatsChartEmbeddableFactory = ( const { toasts } = deps.notifications; - const serializeState = () => { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...serializeFieldStatsChartState(), - }; - }; - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -213,10 +207,15 @@ export const getFieldStatsChartEmbeddableFactory = ( ...fieldStatsControlsComparators, ...timeRangeComparators, }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - timeRangeManager.reinitializeState(lastSaved); - fieldStatsStateManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...serializeFieldStatsChartState(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + timeRangeManager.reinitializeState(nextState); + fieldStatsStateManager.reinitializeState(nextState); }, }); @@ -224,7 +223,7 @@ export const getFieldStatsChartEmbeddableFactory = ( ...timeRangeManager.api, ...titleManager.api, ...fieldStatsControlsApi, - ...unsavedChangesApi, + ...containerStateApi, // PublishesDataLoading dataLoading$, // PublishesBlockingError @@ -262,7 +261,6 @@ export const getFieldStatsChartEmbeddableFactory = ( }); }, dataViews$, - serializeState, }); const reload$ = fetch$(api).pipe( diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx index c670f979b19a4..9a62f13fe21bf 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx @@ -21,7 +21,6 @@ import { titleComparators, timeRangeComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import fastIsEqual from 'fast-deep-equal'; import React, { useMemo } from 'react'; @@ -43,7 +42,13 @@ export const getChangePointChartEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_CHANGE_POINT_CHART_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const [coreStart, pluginStart] = await getStartServices(); const timeRangeManager = initializeTimeRangeManager(initialState); @@ -62,18 +67,7 @@ export const getChangePointChartEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...changePointManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -86,10 +80,15 @@ export const getChangePointChartEmbeddableFactory = ( ...changePointComparators, }; }, - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) changePointManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...changePointManager.getLatestState(), + }), + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) changePointManager.reinitializeState(nextState); }, }); @@ -97,7 +96,7 @@ export const getChangePointChartEmbeddableFactory = ( ...timeRangeManager.api, ...titleManager.api, ...changePointManager.api, - ...unsavedChangesApi, + ...containerStateApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.changePointDetection.typeDisplayName', { defaultMessage: 'change point charts', @@ -134,7 +133,6 @@ export const getChangePointChartEmbeddableFactory = ( dataLoading$, blockingError$, dataViews$, - serializeState, }); const ChangePointDetectionComponent = getChangePointDetectionComponent( diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx index c85d75a56de03..7232efe712cd8 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx @@ -22,7 +22,6 @@ import { titleComparators, timeRangeComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import fastIsEqual from 'fast-deep-equal'; import React, { useMemo } from 'react'; @@ -42,7 +41,13 @@ export const getLogRateAnalysisEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + initialState, + finalizeApi, + linkToContainerState, + parentApi, + uuid, + }) => { const [coreStart, pluginStart] = await getStartServices(); const runtimeState = initialState; const timeRangeManager = initializeTimeRangeManager(initialState); @@ -62,18 +67,7 @@ export const getLogRateAnalysisEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...serializeLogRateAnalysisChartState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, @@ -84,17 +78,22 @@ export const getLogRateAnalysisEmbeddableFactory = ( ...timeRangeComparators, ...titleComparators, }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - timeRangeManager.reinitializeState(lastSaved); - logRateAnalysisControlsApi.updateUserInput(lastSaved ?? {}); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...serializeLogRateAnalysisChartState(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + timeRangeManager.reinitializeState(nextState); + logRateAnalysisControlsApi.updateUserInput(nextState ?? {}); }, }); const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, ...logRateAnalysisControlsApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.logRateAnalysis.typeDisplayName', { @@ -134,7 +133,6 @@ export const getLogRateAnalysisEmbeddableFactory = ( dataLoading$, blockingError$, dataViews$, - serializeState, }); const LogRateAnalysisEmbeddableWrapper = getLogRateAnalysisEmbeddableWrapperComponent( diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx index 04cb3be8b91ed..0446007f618cb 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx @@ -20,7 +20,6 @@ import { timeRangeComparators, titleComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import fastIsEqual from 'fast-deep-equal'; import React, { useMemo } from 'react'; import useObservable from 'react-use/lib/useObservable'; @@ -38,7 +37,13 @@ export const getPatternAnalysisEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_PATTERN_ANALYSIS_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { const [coreStart, pluginStart] = await getStartServices(); const runtimeState = initialState; const timeRangeManager = initializeTimeRangeManager(initialState); @@ -61,18 +66,7 @@ export const getPatternAnalysisEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...serializePatternAnalysisChartState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, @@ -87,11 +81,16 @@ export const getPatternAnalysisEmbeddableFactory = ( ...titleComparators, ...patternAnalysisControlsComparators, }), - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) { - patternAnalysisControlsApi.updateUserInput(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...serializePatternAnalysisChartState(), + }), + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) { + patternAnalysisControlsApi.updateUserInput(nextState); } }, }); @@ -99,7 +98,7 @@ export const getPatternAnalysisEmbeddableFactory = ( const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, ...patternAnalysisControlsApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.patternAnalysis.typeDisplayName', { @@ -131,7 +130,6 @@ export const getPatternAnalysisEmbeddableFactory = ( dataLoading$, blockingError$, dataViews$, - serializeState, }); const PatternAnalysisComponent = getPatternAnalysisComponent(coreStart, pluginStart); diff --git a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx index 390ce1e1a2e70..df318b71f36a8 100644 --- a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx @@ -19,7 +19,6 @@ import { } from '@kbn/presentation-publishing'; import { QueryClientProvider } from '@kbn/react-query'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { openLazyFlyout } from '@kbn/presentation-util'; import { getRuleTypeIdsForSolution } from '@kbn/response-ops-alerts-filters-form/utils/solutions'; import { getInternalRuleTypesWithCache } from '../utils/get_internal_rule_types_with_cache'; @@ -39,7 +38,7 @@ export const getAlertsTableEmbeddableFactory = ( deps: EmbeddableAlertsTablePublicStartDependencies ): EmbeddableFactory => ({ type: EMBEDDABLE_ALERTS_TABLE_ID, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, uuid }) => { const timeRangeManager = initializeTimeRangeManager(initialState); const titleManager = initializeTitleManager(initialState ?? {}); const queryLoading$ = new BehaviorSubject(true); @@ -51,31 +50,27 @@ export const getAlertsTableEmbeddableFactory = ( const initialTableConfig = initialState.tableConfig; const tableConfig$ = new BehaviorSubject(initialTableConfig); - const serializeState = (): EmbeddableAlertsTableSerializedState => ({ - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - tableConfig: tableConfig$.getValue(), - }); - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, tableConfig$ ).pipe(map(() => undefined)), - serializeState, getComparators: () => ({ ...titleComparators, ...timeRangeComparators, tableConfig: 'deepEquality', }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - timeRangeManager.reinitializeState(lastSaved); - if (lastSaved?.tableConfig) { - tableConfig$.next(lastSaved.tableConfig); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + tableConfig: tableConfig$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + timeRangeManager.reinitializeState(nextState); + if (nextState?.tableConfig) { + tableConfig$.next(nextState.tableConfig); } }, }); @@ -89,9 +84,8 @@ export const getAlertsTableEmbeddableFactory = ( const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, dataLoading$: queryLoading$, - serializeState, isEditingEnabled: () => { // Users cannot edit panels based on a solution they cannot access. // The first condition ensures panels are editable even if the table configuration is diff --git a/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx b/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx index 3d9642ae1564a..4aa70744601d2 100644 --- a/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx +++ b/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx @@ -8,7 +8,6 @@ import React from 'react'; import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { initializeTitleManager } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { merge } from 'rxjs'; import type { LensRuntimeState } from '@kbn/lens-common'; import type { LensApi, LensSerializedAPIConfig } from '@kbn/lens-common-2'; @@ -58,6 +57,7 @@ export const createLensEmbeddableFactory = ( initializeDrilldownsManager, initialState, finalizeApi, + linkToContainerState, parentApi, uuid, }) => { @@ -140,15 +140,7 @@ export const createLensEmbeddableFactory = ( }; } - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState: () => { - if (internalApi.isEditingInProgress()) { - return initialState; - } - return integrationsConfig.api.serializeState(); - }, + const containerStateAPi = linkToContainerState({ anyStateChange$: merge( actionsConfig.anyStateChange$, dashboardConfig.anyStateChange$, @@ -174,13 +166,19 @@ export const createLensEmbeddableFactory = ( } return comparators; }, - onReset: async (lastSaved) => { - actionsConfig.reinitializeState(lastSaved); - dashboardConfig.reinitializeState(lastSaved); - searchContextConfig.reinitializeState(lastSaved); - if (!lastSaved) return; - const lastSavedRuntimeState = await deserializeState(services, lastSaved); - stateConfig.reinitializeRuntimeState(lastSavedRuntimeState); + serializeState: () => { + if (internalApi.isEditingInProgress()) { + return initialState; + } + return integrationsConfig.api.serializeState(); + }, + applySerializedState: async (nextState) => { + actionsConfig.reinitializeState(nextState); + dashboardConfig.reinitializeState(nextState); + searchContextConfig.reinitializeState(nextState); + if (!nextState) return; + const nextRuntimeState = await deserializeState(services, nextState); + stateConfig.reinitializeRuntimeState(nextRuntimeState); }, }); @@ -193,7 +191,7 @@ export const createLensEmbeddableFactory = ( // dashboardConfig who owns the savedObjectId after the // stateConfig one who owns the inline editing { - ...unsavedChangesApi, + ...containerStateAPi, ...editConfig.api, ...inspectorConfig.api, ...searchContextConfig.api, 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 b0125bb99646b..2d44146630478 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 @@ -17,7 +17,6 @@ import { titleComparators, useBatchedPublishingSubjects, apiPublishesSettings, - initializeUnsavedChanges, } from '@kbn/presentation-publishing'; import { BehaviorSubject, merge } from 'rxjs'; import { @@ -57,6 +56,7 @@ export const mapEmbeddableFactory: EmbeddableFactory type: MAP_SAVED_OBJECT_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, + linkToContainerState, initialState, finalizeApi, parentApi, @@ -117,15 +117,7 @@ export const mapEmbeddableFactory: EmbeddableFactory return getByValueState(getLatestState(), savedMap.getAttributes()); } - function serializeState() { - const savedObjectId = savedMap.getSavedObjectId(); - return savedObjectId ? serializeByReference(savedObjectId) : serializeByValue(); - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( drilldownsManager.anyStateChange$, crossPanelActions.anyStateChange$, @@ -145,13 +137,17 @@ export const mapEmbeddableFactory: EmbeddableFactory savedObjectId: 'skip', }; }, - onReset: async (lastSaved) => { - drilldownsManager.reinitializeState(lastSaved ?? {}); - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); + serializeState: () => { + const savedObjectId = savedMap.getSavedObjectId(); + return savedObjectId ? serializeByReference(savedObjectId) : serializeByValue(); + }, + applySerializedState: async (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); - if (lastSaved) { - await savedMap.reset(lastSaved); + if (nextState) { + await savedMap.reset(nextState); } }, }); @@ -159,7 +155,7 @@ export const mapEmbeddableFactory: EmbeddableFactory api = finalizeApi({ defaultTitle$, defaultDescription$, - ...unsavedChangesApi, + ...containerStateApi, ...timeRangeManager.api, ...drilldownsManager.api, ...titleManager.api, @@ -183,7 +179,6 @@ export const mapEmbeddableFactory: EmbeddableFactory ), ...initializeDataViews(savedMap.getStore()), ...projectRoutingManager.api, - serializeState, supportedTriggers: () => { return [ON_OPEN_PANEL_MENU, ON_APPLY_FILTER, ON_CLICK_VALUE]; }, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx index 50dbcc972bf33..2d5425b8a3d56 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx @@ -20,7 +20,6 @@ import { initializeTimeRangeManager, initializeTitleManager, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { distinctUntilChanged } from 'rxjs'; import fastIsEqual from 'fast-deep-equal'; import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; @@ -45,7 +44,13 @@ export const getAnomalyChartsReactEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { if (!apiHasExecutionContext(parentApi)) { throw new Error('Parent API does not have execution context'); } @@ -68,18 +73,7 @@ export const getAnomalyChartsReactEmbeddableFactory = ( parentApi ); - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...chartsManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateAPi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -92,10 +86,15 @@ export const getAnomalyChartsReactEmbeddableFactory = ( ...anomalyChartsComparators, }; }, - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) chartsManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...chartsManager.getLatestState(), + }), + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) chartsManager.reinitializeState(nextState); }, }); @@ -133,7 +132,7 @@ export const getAnomalyChartsReactEmbeddableFactory = ( ...timeRangeManager.api, ...chartsManager.api, ...chartsManager.dataLoadingApi, - ...unsavedChangesApi, + ...containerStateAPi, dataViews$: buildDataViewPublishingApi( { anomalyDetectorService: mlServices.anomalyDetectorService, @@ -142,7 +141,6 @@ export const getAnomalyChartsReactEmbeddableFactory = ( { jobIds: chartsManager.api.jobIds$ }, subscriptions ), - serializeState, }); const appliedTimeRange$: Observable = fetch$(api).pipe( diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx index 72d3e1f4594b7..7e94157f1a4b7 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx @@ -29,7 +29,6 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import useUnmount from 'react-use/lib/useUnmount'; import { BehaviorSubject, distinctUntilChanged, map, merge, Subscription } from 'rxjs'; import fastIsEqual from 'fast-deep-equal'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { dispatchRenderComplete, dispatchRenderStart } from '@kbn/kibana-utils-plugin/public'; import { SWIM_LANE_SELECTION_TRIGGER } from '@kbn/ui-actions-plugin/common/trigger_ids'; import type { AnomalySwimlaneEmbeddableServices } from '..'; @@ -88,7 +87,13 @@ export const getAnomalySwimLaneEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + linkToContainerState, + initialState, + finalizeApi, + parentApi, + uuid, + }) => { if (!apiHasExecutionContext(parentApi)) { throw new Error('Parent API does not have execution context'); } @@ -120,18 +125,7 @@ export const getAnomalySwimLaneEmbeddableFactory = ( // Helpers for swim lane data fetching const chartWidth$ = new BehaviorSubject(undefined); - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...swimlaneManager.getLatestState(), - } as AnomalySwimLaneEmbeddableState; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -148,10 +142,16 @@ export const getAnomalySwimLaneEmbeddableFactory = ( filters: 'skip', }; }, - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) swimlaneManager.reinitializeState(lastSaved); + serializeState: () => + ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...swimlaneManager.getLatestState(), + } as AnomalySwimLaneEmbeddableState), + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) swimlaneManager.reinitializeState(nextState); }, }); @@ -187,7 +187,7 @@ export const getAnomalySwimLaneEmbeddableFactory = ( ...titleManager.api, ...timeRangeManager.api, ...swimlaneManager.api, - ...unsavedChangesApi, + ...containerStateApi, query$, filters$, interval, @@ -201,7 +201,6 @@ export const getAnomalySwimLaneEmbeddableFactory = ( subscriptions ), dataLoading$, - serializeState, }); const { swimLaneData$, onDestroy } = initializeSwimLaneDataFetcher( api, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx index 49574734402c5..c96c05f643979 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx @@ -21,7 +21,6 @@ import { useStateFromPublishingSubject, } from '@kbn/presentation-publishing'; import { BehaviorSubject, Subscription, merge } from 'rxjs'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { ANOMALY_SINGLE_METRIC_VIEWER_EMBEDDABLE_TYPE } from '..'; import type { MlPluginStart, MlStartDependencies } from '../../plugin'; import type { SingleMetricViewerEmbeddableApi } from '../types'; @@ -44,7 +43,13 @@ export const getSingleMetricViewerEmbeddableFactory = ( SingleMetricViewerEmbeddableApi > = { type: ANOMALY_SINGLE_METRIC_VIEWER_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ + initialState, + finalizeApi, + linkToContainerState, + uuid, + parentApi, + }) => { const services = await getServices(getStartServices); const subscriptions = new Subscription(); const titleManager = initializeTitleManager(initialState); @@ -58,18 +63,7 @@ export const getSingleMetricViewerEmbeddableFactory = ( const dataLoading$ = new BehaviorSubject(true); const blockingError$ = new BehaviorSubject(undefined); - function serializeState() { - return { - ...titleManager.getLatestState(), - ...timeRangeManager.getLatestState(), - ...singleMetricManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -86,10 +80,15 @@ export const getSingleMetricViewerEmbeddableFactory = ( refreshConfig: 'skip', }; }, - onReset: (lastSaved) => { - timeRangeManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - if (lastSaved) singleMetricManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...timeRangeManager.getLatestState(), + ...singleMetricManager.getLatestState(), + }), + applySerializedState: (nextState) => { + timeRangeManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + if (nextState) singleMetricManager.reinitializeState(nextState); }, }); @@ -130,10 +129,9 @@ export const getSingleMetricViewerEmbeddableFactory = ( ...titleManager.api, ...timeRangeManager.api, ...singleMetricManager.api, - ...unsavedChangesApi, + ...containerStateApi, dataLoading$, blockingError$, - serializeState, }); const { singleMetricViewerData$, onDestroy } = initializeSingleMetricViewerDataFetcher( diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx index fb81ecb71793e..144760f0d387f 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx @@ -12,7 +12,6 @@ import { titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { BehaviorSubject, map, merge } from 'rxjs'; import type { EmbeddableApmAlertingVizProps } from '../types'; import type { EmbeddableDeps } from '../../types'; @@ -26,7 +25,7 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb DefaultEmbeddableApi > = { type: APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const state = initialState; const titleManager = initializeTitleManager(state); const serviceName$ = new BehaviorSubject(state.serviceName); @@ -40,26 +39,7 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - function serializeState(): EmbeddableApmAlertingVizProps { - return { - ...titleManager.getLatestState(), - serviceName: serviceName$.getValue(), - transactionType: transactionType$.getValue(), - transactionName: transactionName$.getValue(), - environment: environment$.getValue(), - rangeFrom: rangeFrom$.getValue(), - rangeTo: rangeTo$.getValue(), - rule: rule$.getValue(), - alert: alert$.getValue(), - kuery: kuery$.getValue(), - filters: filters$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - parentApi, - uuid, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -86,25 +66,37 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb kuery: 'referenceEquality', filters: 'referenceEquality', }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - serviceName$.next(lastSaved?.serviceName ?? ''); - transactionType$.next(lastSaved?.transactionType); - transactionName$.next(lastSaved?.transactionName); - environment$.next(lastSaved?.environment); - rangeFrom$.next(lastSaved?.rangeFrom); - rangeTo$.next(lastSaved?.rangeTo); - rule$.next(lastSaved?.rule as EmbeddableApmAlertingVizProps['rule']); - alert$.next(lastSaved?.alert as EmbeddableApmAlertingVizProps['alert']); - kuery$.next(lastSaved?.kuery); - filters$.next(lastSaved?.filters); + serializeState: () => ({ + ...titleManager.getLatestState(), + serviceName: serviceName$.getValue(), + transactionType: transactionType$.getValue(), + transactionName: transactionName$.getValue(), + environment: environment$.getValue(), + rangeFrom: rangeFrom$.getValue(), + rangeTo: rangeTo$.getValue(), + rule: rule$.getValue(), + alert: alert$.getValue(), + kuery: kuery$.getValue(), + filters: filters$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + serviceName$.next(nextState?.serviceName ?? ''); + transactionType$.next(nextState?.transactionType); + transactionName$.next(nextState?.transactionName); + environment$.next(nextState?.environment); + rangeFrom$.next(nextState?.rangeFrom); + rangeTo$.next(nextState?.rangeTo); + rule$.next(nextState?.rule as EmbeddableApmAlertingVizProps['rule']); + alert$.next(nextState?.alert as EmbeddableApmAlertingVizProps['alert']); + kuery$.next(nextState?.kuery); + filters$.next(nextState?.filters); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, - serializeState, + ...containerStateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx index f1a4381ad2567..9c6f6c6b2c1dc 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx @@ -12,7 +12,6 @@ import { titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { BehaviorSubject, map, merge } from 'rxjs'; import type { EmbeddableApmAlertingLatencyVizProps } from '../types'; import type { EmbeddableDeps } from '../../types'; @@ -26,7 +25,7 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps DefaultEmbeddableApi > = { type: APM_ALERTING_LATENCY_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const state = initialState; const titleManager = initializeTitleManager(state); const serviceName$ = new BehaviorSubject(state.serviceName); @@ -43,27 +42,7 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - function serializeState(): EmbeddableApmAlertingLatencyVizProps { - return { - ...titleManager.getLatestState(), - serviceName: serviceName$.getValue(), - transactionType: transactionType$.getValue(), - transactionName: transactionName$.getValue(), - environment: environment$.getValue(), - latencyThresholdInMicroseconds: latencyThresholdInMicroseconds$.getValue(), - rangeFrom: rangeFrom$.getValue(), - rangeTo: rangeTo$.getValue(), - rule: rule$.getValue(), - alert: alert$.getValue(), - kuery: kuery$.getValue(), - filters: filters$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - parentApi, - uuid, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -92,26 +71,39 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps kuery: 'referenceEquality', filters: 'referenceEquality', }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - serviceName$.next(lastSaved?.serviceName ?? ''); - transactionType$.next(lastSaved?.transactionType); - transactionName$.next(lastSaved?.transactionName); - environment$.next(lastSaved?.environment); - latencyThresholdInMicroseconds$.next(lastSaved?.latencyThresholdInMicroseconds); - rangeFrom$.next(lastSaved?.rangeFrom); - rangeTo$.next(lastSaved?.rangeTo); - rule$.next(lastSaved?.rule as EmbeddableApmAlertingLatencyVizProps['rule']); - alert$.next(lastSaved?.alert as EmbeddableApmAlertingLatencyVizProps['alert']); - kuery$.next(lastSaved?.kuery); - filters$.next(lastSaved?.filters); + serializeState: () => ({ + ...titleManager.getLatestState(), + serviceName: serviceName$.getValue(), + transactionType: transactionType$.getValue(), + transactionName: transactionName$.getValue(), + environment: environment$.getValue(), + latencyThresholdInMicroseconds: latencyThresholdInMicroseconds$.getValue(), + rangeFrom: rangeFrom$.getValue(), + rangeTo: rangeTo$.getValue(), + rule: rule$.getValue(), + alert: alert$.getValue(), + kuery: kuery$.getValue(), + filters: filters$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + serviceName$.next(nextState?.serviceName ?? ''); + transactionType$.next(nextState?.transactionType); + transactionName$.next(nextState?.transactionName); + environment$.next(nextState?.environment); + latencyThresholdInMicroseconds$.next(nextState?.latencyThresholdInMicroseconds); + rangeFrom$.next(nextState?.rangeFrom); + rangeTo$.next(nextState?.rangeTo); + rule$.next(nextState?.rule as EmbeddableApmAlertingLatencyVizProps['rule']); + alert$.next(nextState?.alert as EmbeddableApmAlertingLatencyVizProps['alert']); + kuery$.next(nextState?.kuery); + filters$.next(nextState?.filters); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, - serializeState, + ...containerStateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx index 7abdf0eb97934..9f81415f973dd 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx @@ -10,7 +10,6 @@ import { titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import React from 'react'; import { BehaviorSubject, map, merge } from 'rxjs'; import { ApmEmbeddableContext } from '../../embeddable_context'; @@ -25,7 +24,7 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD DefaultEmbeddableApi > = { type: APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const state = initialState; const titleManager = initializeTitleManager(state); const serviceName$ = new BehaviorSubject(state.serviceName); @@ -39,26 +38,7 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - function serializeState(): EmbeddableApmAlertingVizProps { - return { - ...titleManager.getLatestState(), - serviceName: serviceName$.getValue(), - transactionType: transactionType$.getValue(), - transactionName: transactionName$.getValue(), - environment: environment$.getValue(), - rangeFrom: rangeFrom$.getValue(), - rangeTo: rangeTo$.getValue(), - rule: rule$.getValue(), - alert: alert$.getValue(), - kuery: kuery$.getValue(), - filters: filters$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - parentApi, - uuid, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -85,25 +65,37 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD kuery: 'referenceEquality', filters: 'referenceEquality', }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - serviceName$.next(lastSaved?.serviceName ?? ''); - transactionType$.next(lastSaved?.transactionType); - transactionName$.next(lastSaved?.transactionName); - environment$.next(lastSaved?.environment); - rangeFrom$.next(lastSaved?.rangeFrom); - rangeTo$.next(lastSaved?.rangeTo); - rule$.next(lastSaved?.rule as EmbeddableApmAlertingVizProps['rule']); - alert$.next(lastSaved?.alert as EmbeddableApmAlertingVizProps['alert']); - kuery$.next(lastSaved?.kuery); - filters$.next(lastSaved?.filters); + serializeState: () => ({ + ...titleManager.getLatestState(), + serviceName: serviceName$.getValue(), + transactionType: transactionType$.getValue(), + transactionName: transactionName$.getValue(), + environment: environment$.getValue(), + rangeFrom: rangeFrom$.getValue(), + rangeTo: rangeTo$.getValue(), + rule: rule$.getValue(), + alert: alert$.getValue(), + kuery: kuery$.getValue(), + filters: filters$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + serviceName$.next(nextState?.serviceName ?? ''); + transactionType$.next(nextState?.transactionType); + transactionName$.next(nextState?.transactionName); + environment$.next(nextState?.environment); + rangeFrom$.next(nextState?.rangeFrom); + rangeTo$.next(nextState?.rangeTo); + rule$.next(nextState?.rule as EmbeddableApmAlertingVizProps['rule']); + alert$.next(nextState?.alert as EmbeddableApmAlertingVizProps['alert']); + kuery$.next(nextState?.kuery); + filters$.next(nextState?.filters); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, - serializeState, + ...containerStateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx index c279ab887bc58..9747073fa80dd 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx @@ -22,7 +22,6 @@ import { import { QueryClient, QueryClientProvider } from '@kbn/react-query'; import React, { useEffect } from 'react'; import { BehaviorSubject, Subject, merge } from 'rxjs'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { PluginContext } from '../../../context/plugin_context'; import type { SLOPublicPluginsStart, SLORepositoryClient } from '../../../types'; import { SLO_ALERTS_EMBEDDABLE_ID } from './constants'; @@ -49,7 +48,7 @@ export function getAlertsEmbeddableFactory({ }) { const factory: EmbeddableFactory = { type: SLO_ALERTS_EMBEDDABLE_ID, - buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const deps = { ...coreStart, ...pluginsStart }; async function onEdit() { try { @@ -73,32 +72,26 @@ export function getAlertsEmbeddableFactory({ const defaultTitle$ = new BehaviorSubject(getAlertsPanelTitle()); const reload$ = new Subject(); - function serializeState(): SloAlertsEmbeddableState { - return { - ...titleManager.getLatestState(), - ...sloAlertsStateManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge(titleManager.anyStateChange$, sloAlertsStateManager.anyStateChange$), getComparators: () => ({ ...titleComparators, slos: 'referenceEquality', showAllGroupByInstances: 'referenceEquality', }), - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - sloAlertsStateManager.reinitializeState(lastSaved); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...sloAlertsStateManager.getLatestState(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + sloAlertsStateManager.reinitializeState(nextState); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, defaultTitle$, getTypeDisplayName: () => i18n.translate('xpack.slo.editSloAlertswEmbeddable.typeDisplayName', { @@ -108,7 +101,6 @@ export function getAlertsEmbeddableFactory({ onEdit: async () => { onEdit(); }, - serializeState, getSloAlertsConfig: () => { return { slos: sloAlertsStateManager.api.slos$.getValue(), diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx index e4f12b64aa401..d23576add13b7 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx @@ -7,7 +7,6 @@ import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { fetch$, initializeStateManager, @@ -44,8 +43,7 @@ export const getBurnRateEmbeddableFactory = ({ buildEmbeddable: async ({ initialState, finalizeApi, - uuid, - parentApi, + linkToContainerState, initializeDrilldownsManager, }) => { const deps = { ...coreStart, ...pluginsStart }; @@ -59,23 +57,12 @@ export const getBurnRateEmbeddableFactory = ({ const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); const reload$ = new Subject(); - function serializeState(): BurnRateEmbeddableState { - return { - ...titleManager.getLatestState(), - ...sloBurnRateManager.getLatestState(), - ...drilldownsManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, sloBurnRateManager.anyStateChange$, drilldownsManager.anyStateChange$ ), - serializeState, getComparators: () => ({ ...titleComparators, ...drilldownsManager.comparators, @@ -83,19 +70,23 @@ export const getBurnRateEmbeddableFactory = ({ slo_instance_id: 'referenceEquality', duration: 'referenceEquality', }), - onReset: (lastSaved) => { - sloBurnRateManager.reinitializeState(lastSaved); - titleManager.reinitializeState(lastSaved); - drilldownsManager.reinitializeState(lastSaved ?? {}); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...sloBurnRateManager.getLatestState(), + ...drilldownsManager.getLatestState(), + }), + applySerializedState: (nextState) => { + sloBurnRateManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); + drilldownsManager.reinitializeState(nextState ?? {}); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, ...drilldownsManager.api, defaultTitle$, - serializeState, }); const fetchSubscription = fetch$(api) diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx index 48b74e090eafe..81895a49b8abe 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx @@ -8,7 +8,6 @@ import type { CoreStart } from '@kbn/core-lifecycle-browser'; import type { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { fetch$, initializeStateManager, @@ -50,8 +49,7 @@ export const getErrorBudgetEmbeddableFactory = ({ initializeDrilldownsManager, initialState, finalizeApi, - uuid, - parentApi, + linkToContainerState, }) => { const deps = { ...coreStart, ...pluginsStart }; const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); @@ -63,18 +61,7 @@ export const getErrorBudgetEmbeddableFactory = ({ }); const reload$ = new Subject(); - function serializeState(): ErrorBudgetEmbeddableState { - return { - ...titleManager.getLatestState(), - ...drilldownsManager.getLatestState(), - ...sloErrorBudgetManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( drilldownsManager.anyStateChange$, titleManager.anyStateChange$, @@ -86,20 +73,24 @@ export const getErrorBudgetEmbeddableFactory = ({ slo_id: 'referenceEquality', slo_instance_id: 'referenceEquality', }), - onReset: (lastState) => { - drilldownsManager.reinitializeState(lastState ?? {}); - sloErrorBudgetManager.reinitializeState(lastState); - titleManager.reinitializeState(lastState); + serializeState: () => ({ + ...titleManager.getLatestState(), + ...drilldownsManager.getLatestState(), + ...sloErrorBudgetManager.getLatestState(), + }), + applySerializedState: (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + sloErrorBudgetManager.reinitializeState(nextState); + titleManager.reinitializeState(nextState); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, ...drilldownsManager.api, defaultTitle$, supportedTriggers: () => SLO_ERROR_BUDGET_SUPPORTED_TRIGGERS, - serializeState, }); const fetchSubscription = fetch$(api) diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx index 16ae5e8e40a29..9b1cffa708f34 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx @@ -22,7 +22,6 @@ import { QueryClient, QueryClientProvider } from '@kbn/react-query'; import { ALL_VALUE } from '@kbn/slo-schema'; import React, { useEffect, useMemo } from 'react'; import { BehaviorSubject, Subject, map, merge } from 'rxjs'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { rewriteFiltersForSloSummary } from '../../../../common/rewrite_slo_filters'; import { PluginContext } from '../../../context/plugin_context'; import type { SLOPublicPluginsStart, SLORepositoryClient } from '../../../types'; @@ -58,8 +57,7 @@ export const getOverviewEmbeddableFactory = ({ initializeDrilldownsManager, initialState, finalizeApi, - uuid, - parentApi, + linkToContainerState, }) => { const deps = { ...coreStart, ...pluginsStart }; const state = initialState; @@ -89,35 +87,7 @@ export const getOverviewEmbeddableFactory = ({ const defaultTitle$ = new BehaviorSubject(getOverviewPanelTitle()); const reload$ = new Subject(); - function serializeState(): OverviewEmbeddableState { - const commonState = { - ...titleManager.getLatestState(), - ...drilldownsManager.getLatestState(), - }; - - if (overviewMode$.getValue() === 'single') { - return { - ...commonState, - overview_mode: 'single', - ...singleSloManager.getLatestState(), - }; - } - - if (overviewMode$.getValue() === 'groups') { - return { - ...commonState, - overview_mode: 'groups', - ...groupSloManager.getLatestState(), - }; - } - - throw new Error('overview_mode not provided'); - } - - const unsavedChangesApi = initializeUnsavedChanges({ - uuid, - parentApi, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( drilldownsManager.anyStateChange$, titleManager.anyStateChange$, @@ -134,17 +104,41 @@ export const getOverviewEmbeddableFactory = ({ ...titleComparators, ...drilldownsManager.comparators, }), - onReset: (lastSaved) => { - drilldownsManager.reinitializeState(lastSaved ?? {}); - titleManager.reinitializeState(lastSaved); - singleSloManager.reinitializeState(lastSaved as SingleOverviewCustomState); - groupSloManager.reinitializeState(lastSaved as GroupOverviewCustomState); - setOverviewMode(lastSaved?.overview_mode); + serializeState: () => { + const commonState = { + ...titleManager.getLatestState(), + ...drilldownsManager.getLatestState(), + }; + + if (overviewMode$.getValue() === 'single') { + return { + ...commonState, + overview_mode: 'single', + ...singleSloManager.getLatestState(), + }; + } + + if (overviewMode$.getValue() === 'groups') { + return { + ...commonState, + overview_mode: 'groups', + ...groupSloManager.getLatestState(), + }; + } + + throw new Error('overview_mode not provided'); + }, + applySerializedState: (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + titleManager.reinitializeState(nextState); + singleSloManager.reinitializeState(nextState as SingleOverviewCustomState); + groupSloManager.reinitializeState(nextState as GroupOverviewCustomState); + setOverviewMode(nextState?.overview_mode); }, }); const api = finalizeApi({ - ...unsavedChangesApi, + ...containerStateApi, ...titleManager.api, ...drilldownsManager.api, defaultTitle$, @@ -169,7 +163,6 @@ export const getOverviewEmbeddableFactory = ({ return Promise.reject(); } }, - serializeState, getSloGroupOverviewConfig: (): GroupOverviewCustomState => { return { ...groupSloManager.getLatestState(), diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx index 68944139b44df..ca5046f32f60d 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx @@ -20,7 +20,6 @@ import { fetch$, titleComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { BehaviorSubject, Subject, map, merge } from 'rxjs'; import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; import { StatusGridComponent } from './monitors_grid_component'; @@ -61,7 +60,7 @@ export const getMonitorsEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: SYNTHETICS_MONITORS_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const [coreStart, pluginStart] = await getStartServices(); const titleManager = initializeTitleManager(initialState); @@ -74,18 +73,7 @@ export const getMonitorsEmbeddableFactory = ( }); const view$ = new BehaviorSubject(initialState.view); - function serializeState() { - return { - ...titleManager.getLatestState(), - filters: filters$.getValue(), - view: view$.getValue(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - parentApi, - uuid, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge(titleManager.anyStateChange$, filters$, view$).pipe( map(() => undefined) ), @@ -97,23 +85,27 @@ export const getMonitorsEmbeddableFactory = ( defaultState: { filters: DEFAULT_FILTERS, }, - onReset: (lastSaved) => { - titleManager.reinitializeState(lastSaved); - filters$.next(lastSaved?.filters ?? DEFAULT_FILTERS); - if (lastSaved) view$.next(lastSaved?.view); + serializeState: () => ({ + ...titleManager.getLatestState(), + filters: filters$.getValue(), + view: view$.getValue(), + }), + applySerializedState: (nextState) => { + titleManager.reinitializeState(nextState); + filters$.next(nextState?.filters ?? DEFAULT_FILTERS); + if (nextState) view$.next(nextState?.view); }, }); const api = finalizeApi({ ...titleManager.api, - ...unsavedChangesApi, + ...containerStateApi, defaultTitle$, getTypeDisplayName: () => i18n.translate('xpack.synthetics.editSloOverviewEmbeddableTitle.typeDisplayName', { defaultMessage: 'filters', }), isEditingEnabled: () => true, - serializeState, onEdit: async () => { try { const result = await openMonitorConfiguration({ diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx index 33b1a935f6532..31e20bd17ca9f 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx @@ -25,7 +25,6 @@ import { fetch$, titleComparators, } from '@kbn/presentation-publishing'; -import { initializeUnsavedChanges } from '@kbn/presentation-publishing'; import { BehaviorSubject, Subject, map, merge } from 'rxjs'; import type { StartServicesAccessor } from '@kbn/core-lifecycle-browser'; import type { ClientPluginsStart } from '../../../plugin'; @@ -66,8 +65,7 @@ export const getStatsOverviewEmbeddableFactory = ( initializeDrilldownsManager, initialState, finalizeApi, - parentApi, - uuid, + linkToContainerState, }) => { const [coreStart, pluginStart] = await getStartServices(); @@ -83,18 +81,7 @@ export const getStatsOverviewEmbeddableFactory = ( const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); - function serializeState(): OverviewStatsEmbeddableState { - return { - ...titleManager.getLatestState(), - filters: filters$.getValue(), - ...drilldownsManager.getLatestState(), - }; - } - - const unsavedChangesApi = initializeUnsavedChanges({ - parentApi, - uuid, - serializeState, + const containerStateApi = linkToContainerState({ anyStateChange$: merge( titleManager.anyStateChange$, filters$, @@ -108,17 +95,22 @@ export const getStatsOverviewEmbeddableFactory = ( defaultState: { filters: DEFAULT_FILTERS, }, - onReset: (lastSaved) => { - drilldownsManager.reinitializeState(lastSaved ?? {}); - titleManager.reinitializeState(lastSaved); - filters$.next(lastSaved?.filters ?? DEFAULT_FILTERS); + serializeState: () => ({ + ...titleManager.getLatestState(), + filters: filters$.getValue(), + ...drilldownsManager.getLatestState(), + }), + applySerializedState: (nextState) => { + drilldownsManager.reinitializeState(nextState ?? {}); + titleManager.reinitializeState(nextState); + filters$.next(nextState?.filters ?? DEFAULT_FILTERS); }, }); const api = finalizeApi({ ...titleManager.api, ...drilldownsManager.api, - ...unsavedChangesApi, + ...containerStateApi, supportedTriggers: () => SYNTHETICS_STATS_SUPPORTED_TRIGGERS, defaultTitle$, getTypeDisplayName: () => @@ -145,7 +137,6 @@ export const getStatsOverviewEmbeddableFactory = ( return Promise.reject(); } }, - serializeState, }); const fetchSubscription = fetch$(api) From cb2b32a04361be1000fff405e38401783a9811aa Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 6 Apr 2026 12:56:47 -0400 Subject: [PATCH 02/10] Macroscope fixes. --- .../dashboard_markdown/public/markdown_embeddable.tsx | 2 +- .../public/embeddable/get_search_embeddable_factory.tsx | 1 + .../alerting_latency_chart/react_embeddable_factory.tsx | 6 ++++-- .../embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx | 6 +++++- .../error_budget/error_budget_react_embeddable_factory.tsx | 3 ++- 5 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx index 928aeb0d611f5..8deee97847cc6 100644 --- a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx +++ b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx @@ -113,7 +113,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< // There are no unsaved changes to reset for // by reference 'content' since by reference 'content' is saved on apply. if (!isByReference) { - content$.next((initialState as MarkdownByValueState).content); + content$.next((nextState as MarkdownByValueState).content); } }, }); diff --git a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx index bde3022a78977..08dbe9fa9e21b 100644 --- a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx +++ b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx @@ -226,6 +226,7 @@ export const getSearchEmbeddableFactory = ({ const editApi = initializeEditApi({ uuid, + parentApi, partialApi: { ...searchEmbeddable.api, fetchContext$, savedObjectId$, getSelectedTabId }, discoverServices, isEditable: startServices.isEditable, diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx index 9c6f6c6b2c1dc..d80cd1d85b072 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx @@ -28,6 +28,8 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { const state = initialState; const titleManager = initializeTitleManager(state); + + // TODO, these behaviourSubjects should be replaced with a state manager. const serviceName$ = new BehaviorSubject(state.serviceName); const transactionType$ = new BehaviorSubject(state.transactionType); const transactionName$ = new BehaviorSubject(state.transactionName); @@ -94,10 +96,10 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps latencyThresholdInMicroseconds$.next(nextState?.latencyThresholdInMicroseconds); rangeFrom$.next(nextState?.rangeFrom); rangeTo$.next(nextState?.rangeTo); - rule$.next(nextState?.rule as EmbeddableApmAlertingLatencyVizProps['rule']); - alert$.next(nextState?.alert as EmbeddableApmAlertingLatencyVizProps['alert']); kuery$.next(nextState?.kuery); filters$.next(nextState?.filters); + if (nextState?.rule) rule$.next(nextState.rule); + if (nextState?.alert) alert$.next(nextState.alert); }, }); diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx index 70bf819f0bb7c..e6649cf071040 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx @@ -84,7 +84,11 @@ export function getAlertsEmbeddableFactory({ const reload$ = new Subject(); const containerStateApi = linkToContainerState({ - anyStateChange$: merge(titleManager.anyStateChange$, sloAlertsStateManager.anyStateChange$), + anyStateChange$: merge( + titleManager.anyStateChange$, + drilldownsManager.anyStateChange$, + sloAlertsStateManager.anyStateChange$ + ), getComparators: () => ({ ...titleComparators, ...drilldownsManager.comparators, diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx index 81895a49b8abe..46635e13d1088 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx @@ -47,9 +47,10 @@ export const getErrorBudgetEmbeddableFactory = ({ type: SLO_ERROR_BUDGET_ID, buildEmbeddable: async ({ initializeDrilldownsManager, + linkToContainerState, initialState, finalizeApi, - linkToContainerState, + uuid, }) => { const deps = { ...coreStart, ...pluginsStart }; const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); From e8992ed80b2bcc985175df8213cf269562e897cd Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 6 Apr 2026 14:36:30 -0400 Subject: [PATCH 03/10] update jest tests and add shared mock --- .../embeddable/links_embeddable.test.tsx | 2 ++ .../get_options_list_control_factory.test.tsx | 14 ++++++++++++ .../get_range_slider_control_factory.test.tsx | 10 +++++++++ .../get_esql_control_factory.test.tsx | 8 +++++++ .../get_timeslider_control_factory.test.tsx | 11 ++++++++++ .../public/markdown_embeddable.test.tsx | 4 ++++ .../get_search_embeddable_factory.test.tsx | 19 +++++++++++++++- .../shared/embeddable/public/mocks.tsx | 22 ++++++++++++++++++- .../react_embeddable_renderer.test.tsx | 3 +++ 9 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx b/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx index c0519866ef3f4..7e22450ba8f10 100644 --- a/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx +++ b/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx @@ -17,6 +17,7 @@ import type { Link } from '../../server'; import type { LinksApi, ResolvedLink } from '../types'; import { linksClient } from '../content_management'; import { getMockLinksParentApi } from '../mocks'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; const getLinks = (): Link[] => [ { @@ -116,6 +117,7 @@ async function buildLinksEmbeddable(state: LinksEmbeddableState) { type: LINKS_EMBEDDABLE_TYPE, } as LinksApi; }, + linkToContainerState: getMockLinkToContainerState(factory), parentApi, uuid, }); diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx index b34102d04661d..b3ddddce0796d 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { coreServices, dataViewsService } from '../../../services/kibana_services'; import { getMockedFinalizeApi } from '../../mocks/control_mocks'; import { getOptionsListControlFactory } from './get_options_list_control_factory'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; const render = (ui: React.ReactElement) => { return rtlRender(ui, { wrapper: EuiThemeProvider }); @@ -27,6 +28,8 @@ describe('Options List Control Api', () => { const factory = getOptionsListControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory); + const mockLinkToContainerState = getMockLinkToContainerState(factory); + const getDataView = async (id: string): Promise => { if (id !== 'myDataViewId') { throw new Error(`Simulated error: no data view found for id ${id}`); @@ -81,6 +84,7 @@ describe('Options List Control Api', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -106,6 +110,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['cool', 'test'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -138,6 +143,7 @@ describe('Options List Control Api', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -154,6 +160,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['cool', 'test'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -197,6 +204,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -227,6 +235,7 @@ describe('Options List Control Api', () => { exists_selected: true, exclude: true, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -272,6 +281,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -303,6 +313,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -334,6 +345,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['woof', 'bark'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -370,6 +382,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['woof', 'bark'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, @@ -416,6 +429,7 @@ describe('Options List Control Api', () => { single_select: true, selected_options: ['woof'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: {}, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx index cfda27f023c0c..1ab8936964adf 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx @@ -21,6 +21,7 @@ import { getMockedFinalizeApi } from '../../mocks/control_mocks'; import { getRangesliderControlFactory } from './get_range_slider_control_factory'; import type { RangeSliderControlState } from '@kbn/controls-schemas'; import type { Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; const DEFAULT_TOTAL_RESULTS = 20; const DEFAULT_MIN = 0; @@ -40,6 +41,8 @@ describe('RangeSliderControlApi', () => { const factory = getRangesliderControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory, parentApi); + const mockLinkToContainerState = getMockLinkToContainerState(factory); + let totalResults = DEFAULT_TOTAL_RESULTS; let min: estypes.AggregationsSingleMetricAggregateBase['value'] = DEFAULT_MIN; let max: estypes.AggregationsSingleMetricAggregateBase['value'] = DEFAULT_MAX; @@ -104,6 +107,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -120,6 +124,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -160,6 +165,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -184,6 +190,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -204,6 +211,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -227,6 +235,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, @@ -244,6 +253,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', step: 1024, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi, diff --git a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx index 3e14d64ab7335..3734fb4deb37d 100644 --- a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx @@ -15,6 +15,7 @@ import { DEFAULT_ESQL_OPTIONS_LIST_STATE } from '@kbn/controls-constants'; import { getMockedFinalizeApi } from '../mocks/control_mocks'; import { getESQLControlFactory } from './get_esql_control_factory'; import { BehaviorSubject } from 'rxjs'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; const mockGetESQLSingleColumnValues = jest.fn(() => ({ options: ['option1', 'option2'] })); const mockIsSuccess = jest.fn(() => true); @@ -44,6 +45,8 @@ describe('ESQLControlApi', () => { const factory = getESQLControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory, dashboardApi); + const mockLinkToContainerState = getMockLinkToContainerState(factory); + test('should publish ES|QL variable', async () => { const initialState: OptionsListESQLControlState = { ...DEFAULT_ESQL_OPTIONS_LIST_STATE, @@ -57,6 +60,7 @@ describe('ESQLControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -84,6 +88,7 @@ describe('ESQLControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -114,6 +119,7 @@ describe('ESQLControlApi', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -137,6 +143,7 @@ describe('ESQLControlApi', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -177,6 +184,7 @@ describe('ESQLControlApi', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, diff --git a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx index 86230ab93c7b5..377d9fadc61bb 100644 --- a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx @@ -21,6 +21,7 @@ import { dataService } from '../../services/kibana_services'; import { getMockedFinalizeApi } from '../mocks/control_mocks'; import { getTimesliderControlFactory } from './get_timeslider_control_factory'; import type { TimeSliderControlApi } from './types'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; const render = (ui: React.ReactElement) => { return rtlRender(ui, { wrapper: EuiThemeProvider }); @@ -41,6 +42,8 @@ describe('TimeSliderControlApi', () => { dashboardApi ); + const mockLinkToContainerState = getMockLinkToContainerState(factory); + dataService.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => { const now = new Date(); return { @@ -60,6 +63,7 @@ describe('TimeSliderControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState: DEFAULT_TIME_SLIDER_STATE, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -81,6 +85,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -103,6 +108,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -133,6 +139,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -161,6 +168,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -190,6 +198,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -218,6 +227,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, @@ -250,6 +260,7 @@ describe('TimeSliderControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState: controlState, + linkToContainerState: mockLinkToContainerState, finalizeApi, uuid, parentApi: dashboardApi, diff --git a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx index e705f69213a8b..523fa4e48bc1a 100644 --- a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx +++ b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx @@ -15,6 +15,7 @@ import { BehaviorSubject } from 'rxjs'; import type { ViewMode } from '@kbn/presentation-publishing'; import { markdownEmbeddableFactory } from './markdown_embeddable'; import type { MarkdownEditorApi } from './types'; +import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; jest.mock('./markdown_client/markdown_client', () => { return { @@ -51,12 +52,15 @@ const renderEmbeddable = async ( const factory = markdownEmbeddableFactory; + const mockLinkToContainerState = getMockLinkToContainerState(factory); + const embeddable = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState: { content: '[click here](https://example.com)', }, parentApi: parentApiStub, + linkToContainerState: mockLinkToContainerState, finalizeApi: (api) => ({ ...api, diff --git a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx index 97e8185d1bc43..d48a8c3b1e64a 100644 --- a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx +++ b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx @@ -32,7 +32,10 @@ import type { SearchEmbeddableRuntimeState, } from './types'; import { SolutionType } from '../context_awareness'; -import { mockInitializeDrilldownsManager } from '@kbn/embeddable-plugin/public/mocks'; +import { + mockInitializeDrilldownsManager, + getMockLinkToContainerState, +} from '@kbn/embeddable-plugin/public/mocks'; import { renderWithI18n } from '@kbn/test-jest-helpers'; jest.mock('./utils/serialization_utils', () => ({})); @@ -163,6 +166,8 @@ describe('saved search embeddable', () => { phase$: new BehaviorSubject(undefined), }); + const mockLinkToContainerState = getMockLinkToContainerState(factory); + const waitOneTick = () => act(() => new Promise((resolve) => setTimeout(resolve, 0))); describe('search embeddable component', () => { @@ -172,6 +177,7 @@ describe('saved search embeddable', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -207,6 +213,7 @@ describe('saved search embeddable', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -248,6 +255,7 @@ describe('saved search embeddable', () => { const { Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -268,6 +276,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -289,6 +298,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -326,6 +336,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: byValueInitialState, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeEditableApiMock, uuid, parentApi: mockedEditableDashboardApi, @@ -359,6 +370,7 @@ describe('saved search embeddable', () => { const { api, Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeEditableApiMock, uuid, parentApi: mockedEditableDashboardApi, @@ -412,6 +424,7 @@ describe('saved search embeddable', () => { const { Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -447,6 +460,7 @@ describe('saved search embeddable', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -472,6 +486,7 @@ describe('saved search embeddable', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -499,6 +514,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -532,6 +548,7 @@ describe('saved search embeddable', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { discover_session_id: 'id', overrides: {} }, + linkToContainerState: mockLinkToContainerState, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, diff --git a/src/platform/plugins/shared/embeddable/public/mocks.tsx b/src/platform/plugins/shared/embeddable/public/mocks.tsx index 6cb91d08c1fcd..239fceff1a1f5 100644 --- a/src/platform/plugins/shared/embeddable/public/mocks.tsx +++ b/src/platform/plugins/shared/embeddable/public/mocks.tsx @@ -20,7 +20,7 @@ import type { SavedObjectsTaggingApi } from '@kbn/saved-objects-tagging-oss-plug import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import { BehaviorSubject, of } from 'rxjs'; -import type { EmbeddableStateTransfer } from '.'; +import type { DefaultEmbeddableApi, EmbeddableFactory, EmbeddableStateTransfer } from '.'; import { setKibanaServices } from './kibana_services'; import { EmbeddablePublicPlugin } from './plugin'; import { registerReactEmbeddableFactory } from './react_embeddable_system'; @@ -146,3 +146,23 @@ export async function mockInitializeDrilldownsManager( ): Promise { return mockDrilldownsManager(); } + +export const getMockLinkToContainerState = < + SerializedState extends {} = {}, + ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi +>( + factory: EmbeddableFactory +): jest.Mocked< + Parameters< + EmbeddableFactory['buildEmbeddable'] + >[0]['linkToContainerState'] +> => { + const mockLinkToContainerState: jest.Mocked< + Parameters[0]['linkToContainerState'] + > = ({ serializeState, applySerializedState }) => ({ + serializeState, + applySerializedState, + hasUnsavedChanges$: of(false), + }); + return mockLinkToContainerState; +}; diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx index 580bb4a7d5c97..5ba7ab512b57e 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx @@ -64,6 +64,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), + linkToContainerState: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi: expect.any(Object), uuid: expect.any(String), @@ -88,6 +89,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), + linkToContainerState: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi: expect.any(Object), uuid: '12345', @@ -108,6 +110,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), + linkToContainerState: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi, uuid: expect.any(String), From a548be94da980441572cf498070c83e6a526152f Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 10 Apr 2026 13:35:38 -0400 Subject: [PATCH 04/10] rename to initializeStateApi --- .../data_table_react_embeddable.tsx | 4 +-- .../field_list/field_list_embeddable.tsx | 6 ++-- .../saved_book_react_embeddable.tsx | 6 ++-- .../search/search_react_embeddable.tsx | 6 ++-- .../presentation_publishing/index.ts | 2 +- .../link_to_container_state.ts | 2 +- .../get_image_embeddable_factory.tsx | 6 ++-- .../embeddable/links_embeddable.test.tsx | 4 +-- .../public/embeddable/links_embeddable.tsx | 6 ++-- .../get_options_list_control_factory.test.tsx | 26 ++++++++--------- .../get_options_list_control_factory.tsx | 12 ++------ .../get_range_slider_control_factory.test.tsx | 18 ++++++------ .../get_range_slider_control_factory.tsx | 12 ++------ .../get_esql_control_factory.test.tsx | 14 +++++----- .../esql_control/get_esql_control_factory.tsx | 12 ++------ .../get_timeslider_control_factory.test.tsx | 20 ++++++------- .../get_timeslider_control_factory.tsx | 12 ++------ .../public/markdown_embeddable.test.tsx | 6 ++-- .../public/markdown_embeddable.tsx | 6 ++-- .../get_search_embeddable_factory.test.tsx | 28 +++++++++---------- .../get_search_embeddable_factory.tsx | 6 ++-- .../shared/embeddable/public/mocks.tsx | 10 +++---- .../react_embeddable_renderer.test.tsx | 6 ++-- .../react_embeddable_renderer.tsx | 4 +-- .../public/react_embeddable_system/types.ts | 2 +- .../embeddable/visualize_embeddable.tsx | 4 +-- .../field_stats/field_stats_factory.tsx | 12 ++------ .../embeddable_change_point_chart_factory.tsx | 12 ++------ .../embeddable_log_rate_analysis_factory.tsx | 12 ++------ .../embeddable_pattern_analysis_factory.tsx | 12 ++------ .../alerts_table_embeddable_factory.tsx | 6 ++-- .../react_embeddable/lens_embeddable.tsx | 6 ++-- .../react_embeddable/map_react_embeddable.tsx | 6 ++-- .../anomaly_charts_embeddable_factory.tsx | 12 ++------ .../anomaly_swimlane_embeddable_factory.tsx | 12 ++------ ...ingle_metric_viewer_embeddable_factory.tsx | 12 ++------ .../react_embeddable_factory.tsx | 6 ++-- .../react_embeddable_factory.tsx | 6 ++-- .../react_embeddable_factory.tsx | 6 ++-- .../alerts/slo_alerts_embeddable_factory.tsx | 6 ++-- .../burn_rate_react_embeddable_factory.tsx | 6 ++-- .../error_budget_react_embeddable_factory.tsx | 6 ++-- .../slo/overview/slo_embeddable_factory.tsx | 6 ++-- .../monitors_embeddable_factory.tsx | 6 ++-- .../stats_overview_embeddable_factory.tsx | 6 ++-- 45 files changed, 165 insertions(+), 231 deletions(-) diff --git a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx index 9835c23ecb7ca..e5de96fda2c1c 100644 --- a/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/data_table/data_table_react_embeddable.tsx @@ -37,7 +37,7 @@ export const getDataTableFactory = ( services: StartDeps ): EmbeddableFactory => ({ type: DATA_TABLE_ID, - buildEmbeddable: async ({ initialState, linkToContainerState, finalizeApi, parentApi, uuid }) => { + buildEmbeddable: async ({ initialState, initializeStateApi, finalizeApi, parentApi, uuid }) => { const state = initialState; const timeRangeManager = initializeTimeRangeManager(state); const dataLoading$ = new BehaviorSubject(true); @@ -59,7 +59,7 @@ export const getDataTableFactory = ( }; }; - const containerLinkApi = linkToContainerState({ + const containerLinkApi = initializeStateApi({ serializeState, anyStateChange$: merge(titleManager.anyStateChange$, timeRangeManager.anyStateChange$), getComparators: () => { diff --git a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx index 3287334d3bdd9..68f58eec69e8a 100644 --- a/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/field_list/field_list_embeddable.tsx @@ -84,7 +84,7 @@ export const getFieldListFactory = ( ) => { const fieldListEmbeddableFactory: EmbeddableFactory = { type: FIELD_LIST_ID, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const state = await deserializeState(dataViews, initialState); const allDataViews = await dataViews.getIdsWithTitle(); const subscriptions = new Subscription(); @@ -116,7 +116,7 @@ export const getFieldListFactory = ( }; } - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge(titleManager.anyStateChange$, fieldListStateManager.anyStateChange$), getComparators: () => ({ ...titleComparators, @@ -135,7 +135,7 @@ export const getFieldListFactory = ( const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, }); return { diff --git a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx index 599622e50f502..d473056a96773 100644 --- a/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/saved_book/saved_book_react_embeddable.tsx @@ -49,7 +49,7 @@ const bookStateComparators: StateComparators = { export const getSavedBookEmbeddableFactory = (core: CoreStart) => { const savedBookEmbeddableFactory: EmbeddableFactory = { type: BOOK_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const titleManager = initializeTitleManager(initialState); const savedObjectId = (initialState as BookByReferenceState).savedObjectId; const initialBookState = savedObjectId ? await loadBook(savedObjectId) : initialState; @@ -64,7 +64,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { ...(id ? { savedObjectId: id } : bookStateManager.getLatestState()), }); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge(titleManager.anyStateChange$, bookStateManager.anyStateChange$), getComparators: () => { return { @@ -81,7 +81,7 @@ export const getSavedBookEmbeddableFactory = (core: CoreStart) => { }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...titleManager.api, onEdit: async () => { openLazyFlyout({ diff --git a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx index ff5aec943be07..214791f4245a3 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx +++ b/examples/embeddable_examples/public/react_embeddables/search/search_react_embeddable.tsx @@ -27,7 +27,7 @@ import type { SearchApi, Services, SearchSerializedState } from './types'; export const getSearchEmbeddableFactory = (services: Services) => { const factory: EmbeddableFactory = { type: SEARCH_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const timeRangeManager = initializeTimeRangeManager(initialState); const defaultDataView = await services.dataViews.getDefaultDataView(); const dataViews$ = new BehaviorSubject( @@ -52,7 +52,7 @@ export const getSearchEmbeddableFactory = (services: Services) => { }; } - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: timeRangeManager.anyStateChange$, getComparators: () => { /** @@ -77,7 +77,7 @@ export const getSearchEmbeddableFactory = (services: Services) => { blockingError$, dataViews$, dataLoading$, - ...containerStateApi, + ...stateApi, ...timeRangeManager.api, }); diff --git a/src/platform/packages/shared/presentation/presentation_publishing/index.ts b/src/platform/packages/shared/presentation/presentation_publishing/index.ts index 81ca4db6ad710..3e438776cfdbd 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/index.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/index.ts @@ -209,7 +209,7 @@ export { export { childrenUnsavedChanges$ } from './interfaces/containers/container_state/children_unsaved_changes'; export { - linkToContainerState, + initializeStateApi, type ContainerStateManagerInitializer, } from './interfaces/containers/container_state/link_to_container_state'; diff --git a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts index cdbc2bf9443a6..ab2a6ab649131 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts @@ -27,7 +27,7 @@ export interface ContainerStateManagerInitializer getComparators: () => StateComparators; } -export const linkToContainerState = ({ +export const initializeStateApi = ({ uuid, parentApi, defaultState, diff --git a/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx b/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx index d08702968de5b..095c8dd063857 100644 --- a/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx +++ b/src/platform/plugins/private/image_embeddable/public/image_embeddable/get_image_embeddable_factory.tsx @@ -27,7 +27,7 @@ export const getImageEmbeddableFactory = () => { type: IMAGE_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, - linkToContainerState, + initializeStateApi, initialState, finalizeApi, parentApi, @@ -41,7 +41,7 @@ export const getImageEmbeddableFactory = () => { const imageConfig$ = new BehaviorSubject(initialState.image_config); const dataLoading$ = new BehaviorSubject(true); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, imageConfig$.pipe(map(() => undefined)), @@ -69,7 +69,7 @@ export const getImageEmbeddableFactory = () => { const embeddable = finalizeApi({ ...titleManager.api, ...drilldownsManager.api, - ...containerStateApi, + ...stateApi, dataLoading$, supportedTriggers: () => IMAGE_EMBEDDABLE_SUPPORTED_TRIGGERS, diff --git a/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx b/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx index 7e22450ba8f10..fdb04cf71a434 100644 --- a/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx +++ b/src/platform/plugins/private/links/public/embeddable/links_embeddable.test.tsx @@ -17,7 +17,7 @@ import type { Link } from '../../server'; import type { LinksApi, ResolvedLink } from '../types'; import { linksClient } from '../content_management'; import { getMockLinksParentApi } from '../mocks'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const getLinks = (): Link[] => [ { @@ -117,7 +117,7 @@ async function buildLinksEmbeddable(state: LinksEmbeddableState) { type: LINKS_EMBEDDABLE_TYPE, } as LinksApi; }, - linkToContainerState: getMockLinkToContainerState(factory), + initializeStateApi: getMockinitializeStateApi(factory), parentApi, uuid, }); diff --git a/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx b/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx index 217bcbf10824a..c62797250b0be 100644 --- a/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx +++ b/src/platform/plugins/private/links/public/embeddable/links_embeddable.tsx @@ -48,7 +48,7 @@ export const LinksContext = createContext(null); export const getLinksEmbeddableFactory = () => { const linksEmbeddableFactory: EmbeddableFactory = { type: LINKS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, parentApi }) => { const savedObjectId = (initialState as LinksByReferenceState).savedObjectId; const intialLinksState = savedObjectId ? await loadFromLibrary(savedObjectId) @@ -85,7 +85,7 @@ export const getLinksEmbeddableFactory = () => { }; } - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, layout$.pipe(map(() => undefined)), @@ -127,7 +127,7 @@ export const getLinksEmbeddableFactory = () => { const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, blockingError$, defaultTitle$, defaultDescription$, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx index b3ddddce0796d..1794c6ed02749 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { coreServices, dataViewsService } from '../../../services/kibana_services'; import { getMockedFinalizeApi } from '../../mocks/control_mocks'; import { getOptionsListControlFactory } from './get_options_list_control_factory'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const render = (ui: React.ReactElement) => { return rtlRender(ui, { wrapper: EuiThemeProvider }); @@ -28,7 +28,7 @@ describe('Options List Control Api', () => { const factory = getOptionsListControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory); - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); const getDataView = async (id: string): Promise => { if (id !== 'myDataViewId') { @@ -84,7 +84,7 @@ describe('Options List Control Api', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -110,7 +110,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['cool', 'test'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -143,7 +143,7 @@ describe('Options List Control Api', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -160,7 +160,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['cool', 'test'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -204,7 +204,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -235,7 +235,7 @@ describe('Options List Control Api', () => { exists_selected: true, exclude: true, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -281,7 +281,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -313,7 +313,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', exists_selected: true, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -345,7 +345,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['woof', 'bark'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -382,7 +382,7 @@ describe('Options List Control Api', () => { field_name: 'myFieldName', selected_options: ['woof', 'bark'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, @@ -429,7 +429,7 @@ describe('Options List Control Api', () => { single_select: true, selected_options: ['woof'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: {}, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx index 0035cc328f6d1..df6982a30e5cf 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx @@ -65,13 +65,7 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< > => { return { type: OPTIONS_LIST_CONTROL, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const state = initialState; const editorStateManager = initializeEditorStateManager(state); @@ -236,7 +230,7 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< } ); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( dataControlManager.anyStateChange$, selectionsManager.anyStateChange$, @@ -285,7 +279,7 @@ export const getOptionsListControlFactory = (): EmbeddableFactory< .subscribe((error) => blockingError$.next(error)); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...dataControlManager.api, blockingError$, dataLoading$: temporaryStateManager.api.dataLoading$, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx index 1ab8936964adf..f08b2a52f9929 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.test.tsx @@ -21,7 +21,7 @@ import { getMockedFinalizeApi } from '../../mocks/control_mocks'; import { getRangesliderControlFactory } from './get_range_slider_control_factory'; import type { RangeSliderControlState } from '@kbn/controls-schemas'; import type { Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const DEFAULT_TOTAL_RESULTS = 20; const DEFAULT_MIN = 0; @@ -41,7 +41,7 @@ describe('RangeSliderControlApi', () => { const factory = getRangesliderControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory, parentApi); - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); let totalResults = DEFAULT_TOTAL_RESULTS; let min: estypes.AggregationsSingleMetricAggregateBase['value'] = DEFAULT_MIN; @@ -107,7 +107,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -124,7 +124,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -165,7 +165,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -190,7 +190,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', value: ['5', '10'], }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -211,7 +211,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -235,7 +235,7 @@ describe('RangeSliderControlApi', () => { data_view_id: 'myDataViewId', field_name: 'myFieldName', }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, @@ -253,7 +253,7 @@ describe('RangeSliderControlApi', () => { field_name: 'myFieldName', step: 1024, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi, diff --git a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx index 601c44715011d..37371f2b20d34 100644 --- a/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/data_controls/range_slider/get_range_slider_control_factory.tsx @@ -41,13 +41,7 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< > => { return { type: RANGE_SLIDER_CONTROL, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const state = initialState; const loadingMinMax$ = new BehaviorSubject(false); const loadingHasNoResults$ = new BehaviorSubject(false); @@ -73,7 +67,7 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< dataControlManager.internalApi.onSelectionChange ); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( dataControlManager.anyStateChange$, selections.value$, @@ -99,7 +93,7 @@ export const getRangesliderControlFactory = (): EmbeddableFactory< }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...dataControlManager.api, dataLoading$, clearSelections: () => { diff --git a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx index ce3153b6d388f..2abc9decdc10a 100644 --- a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.test.tsx @@ -15,7 +15,7 @@ import { DEFAULT_ESQL_OPTIONS_LIST_STATE } from '@kbn/controls-constants'; import { getMockedFinalizeApi } from '../mocks/control_mocks'; import { getESQLControlFactory } from './get_esql_control_factory'; import { BehaviorSubject } from 'rxjs'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const mockGetESQLSingleColumnValues = jest.fn(() => ({ options: ['option1', 'option2'] })); const mockIsSuccess = jest.fn(() => true); @@ -45,7 +45,7 @@ describe('ESQLControlApi', () => { const factory = getESQLControlFactory(); const finalizeApi = getMockedFinalizeApi(uuid, factory, dashboardApi); - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); test('should publish ES|QL variable', async () => { const initialState: OptionsListESQLControlState = { @@ -59,7 +59,7 @@ describe('ESQLControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -86,7 +86,7 @@ describe('ESQLControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -115,7 +115,7 @@ describe('ESQLControlApi', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -139,7 +139,7 @@ describe('ESQLControlApi', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -179,7 +179,7 @@ describe('ESQLControlApi', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, diff --git a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx index 60abc48722ed6..eb5eee6415ee3 100644 --- a/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/esql_control/get_esql_control_factory.tsx @@ -40,13 +40,7 @@ export const getESQLControlFactory = < > => { return { type: ESQL_CONTROL, - buildEmbeddable: async ({ - uuid, - parentApi, - finalizeApi, - initialState, - linkToContainerState, - }) => { + buildEmbeddable: async ({ uuid, parentApi, finalizeApi, initialState, initializeStateApi }) => { const state = initialState; const dataLoading$ = new BehaviorSubject(false); @@ -58,7 +52,7 @@ export const getESQLControlFactory = < selections.internalApi, 'variableName' ); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: selections.anyStateChange$, getComparators: () => { return { @@ -82,7 +76,7 @@ export const getESQLControlFactory = < }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...selections.api, ...labelManager.api, dataLoading$, diff --git a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx index 377d9fadc61bb..fbfd5b119ac82 100644 --- a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx +++ b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.test.tsx @@ -21,7 +21,7 @@ import { dataService } from '../../services/kibana_services'; import { getMockedFinalizeApi } from '../mocks/control_mocks'; import { getTimesliderControlFactory } from './get_timeslider_control_factory'; import type { TimeSliderControlApi } from './types'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const render = (ui: React.ReactElement) => { return rtlRender(ui, { wrapper: EuiThemeProvider }); @@ -42,7 +42,7 @@ describe('TimeSliderControlApi', () => { dashboardApi ); - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); dataService.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => { const now = new Date(); @@ -63,7 +63,7 @@ describe('TimeSliderControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState: DEFAULT_TIME_SLIDER_STATE, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -85,7 +85,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -108,7 +108,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -139,7 +139,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -168,7 +168,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -198,7 +198,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -227,7 +227,7 @@ describe('TimeSliderControlApi', () => { start_percentage_of_time_range: 0.25, end_percentage_of_time_range: 0.5, }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, @@ -260,7 +260,7 @@ describe('TimeSliderControlApi', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), initialState: controlState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi, uuid, parentApi: dashboardApi, diff --git a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx index cb790c0b9fd85..d39eabb66c0cb 100644 --- a/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx +++ b/src/platform/plugins/shared/controls/public/controls/timeslider_control/get_timeslider_control_factory.tsx @@ -52,13 +52,7 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< > => { return { type: TIME_SLIDER_CONTROL, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const state = initialState; const { timeRangeMeta$, formatDate, cleanupTimeRangeSubscription } = @@ -228,7 +222,7 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< }) ); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( timeRangePercentage.anyStateChange$, isAnchored$.pipe(map(() => undefined)) @@ -251,7 +245,7 @@ export const getTimesliderControlFactory = (): EmbeddableFactory< }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, isPinnable: false, // Disable the user-facing unpin action; panel can still be pinned programatically when it's created label$: new BehaviorSubject(displayName), appliedTimeslice$: timeslice$, diff --git a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx index b116de347e4f0..27fdc9d1e67e5 100644 --- a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx +++ b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.test.tsx @@ -15,7 +15,7 @@ import { BehaviorSubject } from 'rxjs'; import type { ViewMode } from '@kbn/presentation-publishing'; import { markdownEmbeddableFactory } from './markdown_embeddable'; import type { MarkdownEditorApi } from './types'; -import { getMockLinkToContainerState } from '@kbn/embeddable-plugin/public/mocks'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; jest.mock('./markdown_client/markdown_client', () => { return { @@ -52,7 +52,7 @@ const renderEmbeddable = async ( const factory = markdownEmbeddableFactory; - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); const embeddable = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), @@ -60,7 +60,7 @@ const renderEmbeddable = async ( content: '[click here](https://example.com)', }, parentApi: parentApiStub, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: (api) => ({ ...api, diff --git a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx index b67be75d42eda..1c1a312b2bb98 100644 --- a/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx +++ b/src/platform/plugins/shared/dashboard_markdown/public/markdown_embeddable.tsx @@ -49,7 +49,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< MarkdownEditorApi > = { type: MARKDOWN_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, parentApi }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, parentApi }) => { const libraryId = (initialState as MarkdownByReferenceState).ref_id; const isByReference = libraryId !== undefined; const initialLibraryState = isByReference @@ -106,7 +106,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< } }; - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, content$.pipe(map(() => undefined)), @@ -137,7 +137,7 @@ export const markdownEmbeddableFactory: EmbeddableFactory< }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...titleManager.api, defaultTitle$, defaultDescription$, diff --git a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx index 84fe68218b4ce..84ed7f9266d45 100644 --- a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx +++ b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.test.tsx @@ -34,7 +34,7 @@ import type { import { SolutionType } from '../context_awareness'; import { mockInitializeDrilldownsManager, - getMockLinkToContainerState, + getMockinitializeStateApi, } from '@kbn/embeddable-plugin/public/mocks'; import { renderWithI18n } from '@kbn/test-jest-helpers'; @@ -166,7 +166,7 @@ describe('saved search embeddable', () => { phase$: new BehaviorSubject(undefined), }); - const mockLinkToContainerState = getMockLinkToContainerState(factory); + const mockinitializeStateApi = getMockinitializeStateApi(factory); const waitOneTick = () => act(() => new Promise((resolve) => setTimeout(resolve, 0))); @@ -176,7 +176,7 @@ describe('saved search embeddable', () => { runtimeState = getInitialRuntimeState({ searchMock: search }); const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, initialState: { ref_id: 'id', overrides: {} }, finalizeApi: finalizeApiMock, uuid, @@ -213,7 +213,7 @@ describe('saved search embeddable', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -255,7 +255,7 @@ describe('saved search embeddable', () => { const { Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -276,7 +276,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -298,7 +298,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -336,7 +336,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: byValueInitialState, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeEditableApiMock, uuid, parentApi: mockedEditableDashboardApi, @@ -370,7 +370,7 @@ describe('saved search embeddable', () => { const { api, Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeEditableApiMock, uuid, parentApi: mockedEditableDashboardApi, @@ -424,7 +424,7 @@ describe('saved search embeddable', () => { const { Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { savedObjectId: 'id' }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -460,7 +460,7 @@ describe('saved search embeddable', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -486,7 +486,7 @@ describe('saved search embeddable', () => { await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -514,7 +514,7 @@ describe('saved search embeddable', () => { const { api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, @@ -548,7 +548,7 @@ describe('saved search embeddable', () => { const { Component, api } = await factory.buildEmbeddable({ initializeDrilldownsManager: mockInitializeDrilldownsManager, initialState: { ref_id: 'id', overrides: {} }, - linkToContainerState: mockLinkToContainerState, + initializeStateApi: mockinitializeStateApi, finalizeApi: finalizeApiMock, uuid, parentApi: mockedDashboardApi, diff --git a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx index dfaf239c87b5d..1a8a628a30699 100644 --- a/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx +++ b/src/platform/plugins/shared/discover/public/embeddable/get_search_embeddable_factory.tsx @@ -68,7 +68,7 @@ export const getSearchEmbeddableFactory = ({ type: SEARCH_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, - linkToContainerState, + initializeStateApi, initialState, finalizeApi, parentApi, @@ -152,7 +152,7 @@ export const getSearchEmbeddableFactory = ({ searchEmbeddable, }); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( drilldownsManager.anyStateChange$, searchEmbeddable.anyStateChange$, @@ -211,7 +211,7 @@ export const getSearchEmbeddableFactory = ({ }); const api: SearchEmbeddableApi = finalizeApi({ - ...containerStateApi, + ...stateApi, ...titleManager.api, ...searchEmbeddable.api, ...timeRangeManager.api, diff --git a/src/platform/plugins/shared/embeddable/public/mocks.tsx b/src/platform/plugins/shared/embeddable/public/mocks.tsx index 239fceff1a1f5..38ca92172b4ec 100644 --- a/src/platform/plugins/shared/embeddable/public/mocks.tsx +++ b/src/platform/plugins/shared/embeddable/public/mocks.tsx @@ -147,7 +147,7 @@ export async function mockInitializeDrilldownsManager( return mockDrilldownsManager(); } -export const getMockLinkToContainerState = < +export const getMockinitializeStateApi = < SerializedState extends {} = {}, ApiType extends DefaultEmbeddableApi = DefaultEmbeddableApi >( @@ -155,14 +155,14 @@ export const getMockLinkToContainerState = < ): jest.Mocked< Parameters< EmbeddableFactory['buildEmbeddable'] - >[0]['linkToContainerState'] + >[0]['initializeStateApi'] > => { - const mockLinkToContainerState: jest.Mocked< - Parameters[0]['linkToContainerState'] + const mockinitializeStateApi: jest.Mocked< + Parameters[0]['initializeStateApi'] > = ({ serializeState, applySerializedState }) => ({ serializeState, applySerializedState, hasUnsavedChanges$: of(false), }); - return mockLinkToContainerState; + return mockinitializeStateApi; }; diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx index 5ba7ab512b57e..58da16719aeea 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.test.tsx @@ -64,7 +64,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), - linkToContainerState: expect.any(Function), + initializeStateApi: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi: expect.any(Object), uuid: expect.any(String), @@ -89,7 +89,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), - linkToContainerState: expect.any(Function), + initializeStateApi: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi: expect.any(Object), uuid: '12345', @@ -110,7 +110,7 @@ describe('embeddable renderer', () => { await waitFor(() => { expect(buildEmbeddableSpy).toHaveBeenCalledWith({ initializeDrilldownsManager: expect.any(Function), - linkToContainerState: expect.any(Function), + initializeStateApi: expect.any(Function), initialState: { bork: 'blorp?' }, parentApi, uuid: expect.any(String), diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index 22825ce16c416..c3a3540ebbea4 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -10,7 +10,7 @@ import type { PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; import { PresentationPanel } from '@kbn/presentation-panel-plugin/public'; import type { HasPanelCapabilities, HasSerializedChildState } from '@kbn/presentation-publishing'; -import { apiIsPresentationContainer, linkToContainerState } from '@kbn/presentation-publishing'; +import { apiIsPresentationContainer, initializeStateApi } from '@kbn/presentation-publishing'; import React, { useImperativeHandle, useMemo, useRef } from 'react'; import { BehaviorSubject } from 'rxjs'; import { v4 as generateId } from 'uuid'; @@ -99,7 +99,7 @@ export const EmbeddableRenderer = < finalizeApi, uuid, parentApi, - linkToContainerState: (args) => linkToContainerState({ ...args, uuid, parentApi }), + initializeStateApi: (args) => initializeStateApi({ ...args, uuid, parentApi }), initializeDrilldownsManager: async ( embeddableUuid: string, state: SerializedDrilldowns diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts index 1ee2564893213..7090827fb2208 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts @@ -67,7 +67,7 @@ export interface BuildEmbeddableProps< /** * Initializes and returns all APIs required for the parent to interact with the state of this API. */ - linkToContainerState: ( + initializeStateApi: ( args: ContainerStateManagerInitializer ) => PublishesUnsavedChanges & HasSerializableState; diff --git a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx index 00d92b34babca..1ae5ed4bb2762 100644 --- a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx @@ -62,7 +62,7 @@ export const visualizeEmbeddableFactory: EmbeddableFactory = { type: FIELD_STATS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const [coreStart, pluginStart] = await getStartServices(); const { http, uiSettings, notifications, ...startServices } = coreStart; @@ -196,7 +190,7 @@ export const getFieldStatsChartEmbeddableFactory = ( const { toasts } = deps.notifications; - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -223,7 +217,7 @@ export const getFieldStatsChartEmbeddableFactory = ( ...timeRangeManager.api, ...titleManager.api, ...fieldStatsControlsApi, - ...containerStateApi, + ...stateApi, // PublishesDataLoading dataLoading$, // PublishesBlockingError diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx index 9a62f13fe21bf..fbb214cd99d6f 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/change_point_chart/embeddable_change_point_chart_factory.tsx @@ -42,13 +42,7 @@ export const getChangePointChartEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_CHANGE_POINT_CHART_TYPE, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const [coreStart, pluginStart] = await getStartServices(); const timeRangeManager = initializeTimeRangeManager(initialState); @@ -67,7 +61,7 @@ export const getChangePointChartEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -96,7 +90,7 @@ export const getChangePointChartEmbeddableFactory = ( ...timeRangeManager.api, ...titleManager.api, ...changePointManager.api, - ...containerStateApi, + ...stateApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.changePointDetection.typeDisplayName', { defaultMessage: 'change point charts', diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx index 7232efe712cd8..082f669592229 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx @@ -41,13 +41,7 @@ export const getLogRateAnalysisEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE, - buildEmbeddable: async ({ - initialState, - finalizeApi, - linkToContainerState, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, parentApi, uuid }) => { const [coreStart, pluginStart] = await getStartServices(); const runtimeState = initialState; const timeRangeManager = initializeTimeRangeManager(initialState); @@ -67,7 +61,7 @@ export const getLogRateAnalysisEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, @@ -93,7 +87,7 @@ export const getLogRateAnalysisEmbeddableFactory = ( const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...containerStateApi, + ...stateApi, ...logRateAnalysisControlsApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.logRateAnalysis.typeDisplayName', { diff --git a/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx b/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx index 0446007f618cb..1b722ba651030 100644 --- a/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx +++ b/x-pack/platform/plugins/shared/aiops/public/embeddables/pattern_analysis/embeddable_pattern_analysis_factory.tsx @@ -37,13 +37,7 @@ export const getPatternAnalysisEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: EMBEDDABLE_PATTERN_ANALYSIS_TYPE, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { const [coreStart, pluginStart] = await getStartServices(); const runtimeState = initialState; const timeRangeManager = initializeTimeRangeManager(initialState); @@ -66,7 +60,7 @@ export const getPatternAnalysisEmbeddableFactory = ( const filtersApi = apiPublishesFilters(parentApi) ? parentApi : undefined; - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, @@ -98,7 +92,7 @@ export const getPatternAnalysisEmbeddableFactory = ( const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...containerStateApi, + ...stateApi, ...patternAnalysisControlsApi, getTypeDisplayName: () => i18n.translate('xpack.aiops.patternAnalysis.typeDisplayName', { diff --git a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx index df318b71f36a8..65c90cefc874a 100644 --- a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.tsx @@ -38,7 +38,7 @@ export const getAlertsTableEmbeddableFactory = ( deps: EmbeddableAlertsTablePublicStartDependencies ): EmbeddableFactory => ({ type: EMBEDDABLE_ALERTS_TABLE_ID, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState, uuid }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, uuid }) => { const timeRangeManager = initializeTimeRangeManager(initialState); const titleManager = initializeTitleManager(initialState ?? {}); const queryLoading$ = new BehaviorSubject(true); @@ -50,7 +50,7 @@ export const getAlertsTableEmbeddableFactory = ( const initialTableConfig = initialState.tableConfig; const tableConfig$ = new BehaviorSubject(initialTableConfig); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( timeRangeManager.anyStateChange$, titleManager.anyStateChange$, @@ -84,7 +84,7 @@ export const getAlertsTableEmbeddableFactory = ( const api = finalizeApi({ ...timeRangeManager.api, ...titleManager.api, - ...containerStateApi, + ...stateApi, dataLoading$: queryLoading$, isEditingEnabled: () => { // Users cannot edit panels based on a solution they cannot access. diff --git a/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx b/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx index 18ee4e10a3a46..2a2d90f97da45 100644 --- a/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx +++ b/x-pack/platform/plugins/shared/lens/public/react_embeddable/lens_embeddable.tsx @@ -56,7 +56,7 @@ export const createLensEmbeddableFactory = ( initializeDrilldownsManager, initialState, finalizeApi, - linkToContainerState, + initializeStateApi, parentApi, uuid, }) => { @@ -139,7 +139,7 @@ export const createLensEmbeddableFactory = ( }; } - const containerStateAPi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( actionsConfig.anyStateChange$, dashboardConfig.anyStateChange$, @@ -190,7 +190,7 @@ export const createLensEmbeddableFactory = ( // dashboardConfig who owns the savedObjectId after the // stateConfig one who owns the inline editing { - ...containerStateAPi, + ...stateApi, ...editConfig.api, ...inspectorConfig.api, ...searchContextConfig.api, 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 2d44146630478..92d50ffdad9d3 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 @@ -56,7 +56,7 @@ export const mapEmbeddableFactory: EmbeddableFactory type: MAP_SAVED_OBJECT_TYPE, buildEmbeddable: async ({ initializeDrilldownsManager, - linkToContainerState, + initializeStateApi, initialState, finalizeApi, parentApi, @@ -117,7 +117,7 @@ export const mapEmbeddableFactory: EmbeddableFactory return getByValueState(getLatestState(), savedMap.getAttributes()); } - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( drilldownsManager.anyStateChange$, crossPanelActions.anyStateChange$, @@ -155,7 +155,7 @@ export const mapEmbeddableFactory: EmbeddableFactory api = finalizeApi({ defaultTitle$, defaultDescription$, - ...containerStateApi, + ...stateApi, ...timeRangeManager.api, ...drilldownsManager.api, ...titleManager.api, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx index 68b83fd829233..18f1c68fe4661 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_charts/anomaly_charts_embeddable_factory.tsx @@ -46,13 +46,7 @@ export const getAnomalyChartsReactEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: ANOMALY_EXPLORER_CHARTS_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { if (!apiHasExecutionContext(parentApi)) { throw new Error('Parent API does not have execution context'); } @@ -76,7 +70,7 @@ export const getAnomalyChartsReactEmbeddableFactory = ( parentApi ); - const containerStateAPi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -135,7 +129,7 @@ export const getAnomalyChartsReactEmbeddableFactory = ( ...timeRangeManager.api, ...chartsManager.api, ...chartsManager.dataLoadingApi, - ...containerStateAPi, + ...stateApi, dataViews$: buildDataViewPublishingApi( { anomalyDetectorService: mlServices.anomalyDetectorService, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx index 7e94157f1a4b7..740906af1b560 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.tsx @@ -87,13 +87,7 @@ export const getAnomalySwimLaneEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: ANOMALY_SWIMLANE_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ - linkToContainerState, - initialState, - finalizeApi, - parentApi, - uuid, - }) => { + buildEmbeddable: async ({ initializeStateApi, initialState, finalizeApi, parentApi, uuid }) => { if (!apiHasExecutionContext(parentApi)) { throw new Error('Parent API does not have execution context'); } @@ -125,7 +119,7 @@ export const getAnomalySwimLaneEmbeddableFactory = ( // Helpers for swim lane data fetching const chartWidth$ = new BehaviorSubject(undefined); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -187,7 +181,7 @@ export const getAnomalySwimLaneEmbeddableFactory = ( ...titleManager.api, ...timeRangeManager.api, ...swimlaneManager.api, - ...containerStateApi, + ...stateApi, query$, filters$, interval, diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx index b2c1126f454ac..6b6a3c5037e11 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx @@ -45,13 +45,7 @@ export const getSingleMetricViewerEmbeddableFactory = ( SingleMetricViewerEmbeddableApi > = { type: ANOMALY_SINGLE_METRIC_VIEWER_EMBEDDABLE_TYPE, - buildEmbeddable: async ({ - initialState, - finalizeApi, - linkToContainerState, - uuid, - parentApi, - }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, uuid, parentApi }) => { const services = await getServices(getStartServices); const subscriptions = new Subscription(); const titleManager = initializeTitleManager(initialState); @@ -65,7 +59,7 @@ export const getSingleMetricViewerEmbeddableFactory = ( const dataLoading$ = new BehaviorSubject(true); const blockingError$ = new BehaviorSubject(undefined); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, timeRangeManager.anyStateChange$, @@ -131,7 +125,7 @@ export const getSingleMetricViewerEmbeddableFactory = ( ...titleManager.api, ...timeRangeManager.api, ...singleMetricManager.api, - ...containerStateApi, + ...stateApi, dataLoading$, blockingError$, }); diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx index 144760f0d387f..296b7fde929ff 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_failed_transactions_chart/react_embeddable_factory.tsx @@ -25,7 +25,7 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb DefaultEmbeddableApi > = { type: APM_ALERTING_FAILED_TRANSACTIONS_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const state = initialState; const titleManager = initializeTitleManager(state); const serviceName$ = new BehaviorSubject(state.serviceName); @@ -39,7 +39,7 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -96,7 +96,7 @@ export const getApmAlertingFailedTransactionsChartEmbeddableFactory = (deps: Emb const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx index d80cd1d85b072..4365a1889a736 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_latency_chart/react_embeddable_factory.tsx @@ -25,7 +25,7 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps DefaultEmbeddableApi > = { type: APM_ALERTING_LATENCY_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const state = initialState; const titleManager = initializeTitleManager(state); @@ -44,7 +44,7 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -105,7 +105,7 @@ export const getApmAlertingLatencyChartEmbeddableFactory = (deps: EmbeddableDeps const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx index 9f81415f973dd..71ec08432c239 100644 --- a/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/apm/public/embeddable/alerting/alerting_throughput_chart/react_embeddable_factory.tsx @@ -24,7 +24,7 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD DefaultEmbeddableApi > = { type: APM_ALERTING_THROUGHPUT_CHART_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const state = initialState; const titleManager = initializeTitleManager(state); const serviceName$ = new BehaviorSubject(state.serviceName); @@ -38,7 +38,7 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD const kuery$ = new BehaviorSubject(state.kuery); const filters$ = new BehaviorSubject(state.filters); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, serviceName$, @@ -95,7 +95,7 @@ export const getApmAlertingThroughputChartEmbeddableFactory = (deps: EmbeddableD const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, }); return { diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx index e6649cf071040..bfd9169555808 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/alerts/slo_alerts_embeddable_factory.tsx @@ -53,7 +53,7 @@ export function getAlertsEmbeddableFactory({ type: SLO_ALERTS_EMBEDDABLE_ID, buildEmbeddable: async ({ initializeDrilldownsManager, - linkToContainerState, + initializeStateApi, initialState, finalizeApi, parentApi, @@ -83,7 +83,7 @@ export function getAlertsEmbeddableFactory({ const defaultTitle$ = new BehaviorSubject(getAlertsPanelTitle()); const reload$ = new Subject(); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, drilldownsManager.anyStateChange$, @@ -107,7 +107,7 @@ export function getAlertsEmbeddableFactory({ const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, ...drilldownsManager.api, defaultTitle$, supportedTriggers: () => SLO_ALERTS_SUPPORTED_TRIGGERS, diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx index d23576add13b7..31c5dd26733bb 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx @@ -43,7 +43,7 @@ export const getBurnRateEmbeddableFactory = ({ buildEmbeddable: async ({ initialState, finalizeApi, - linkToContainerState, + initializeStateApi, initializeDrilldownsManager, }) => { const deps = { ...coreStart, ...pluginsStart }; @@ -57,7 +57,7 @@ export const getBurnRateEmbeddableFactory = ({ const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); const reload$ = new Subject(); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, sloBurnRateManager.anyStateChange$, @@ -84,7 +84,7 @@ export const getBurnRateEmbeddableFactory = ({ const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, ...drilldownsManager.api, defaultTitle$, }); diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx index 46635e13d1088..b11bbbe10ebdf 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/error_budget/error_budget_react_embeddable_factory.tsx @@ -47,7 +47,7 @@ export const getErrorBudgetEmbeddableFactory = ({ type: SLO_ERROR_BUDGET_ID, buildEmbeddable: async ({ initializeDrilldownsManager, - linkToContainerState, + initializeStateApi, initialState, finalizeApi, uuid, @@ -62,7 +62,7 @@ export const getErrorBudgetEmbeddableFactory = ({ }); const reload$ = new Subject(); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( drilldownsManager.anyStateChange$, titleManager.anyStateChange$, @@ -88,7 +88,7 @@ export const getErrorBudgetEmbeddableFactory = ({ const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, ...drilldownsManager.api, defaultTitle$, supportedTriggers: () => SLO_ERROR_BUDGET_SUPPORTED_TRIGGERS, diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx index 9b1cffa708f34..3ec1468e16209 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx @@ -57,7 +57,7 @@ export const getOverviewEmbeddableFactory = ({ initializeDrilldownsManager, initialState, finalizeApi, - linkToContainerState, + initializeStateApi, }) => { const deps = { ...coreStart, ...pluginsStart }; const state = initialState; @@ -87,7 +87,7 @@ export const getOverviewEmbeddableFactory = ({ const defaultTitle$ = new BehaviorSubject(getOverviewPanelTitle()); const reload$ = new Subject(); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( drilldownsManager.anyStateChange$, titleManager.anyStateChange$, @@ -138,7 +138,7 @@ export const getOverviewEmbeddableFactory = ({ }); const api = finalizeApi({ - ...containerStateApi, + ...stateApi, ...titleManager.api, ...drilldownsManager.api, defaultTitle$, diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx index ca5046f32f60d..7a03a0c660f61 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/monitors_overview/monitors_embeddable_factory.tsx @@ -60,7 +60,7 @@ export const getMonitorsEmbeddableFactory = ( ) => { const factory: EmbeddableFactory = { type: SYNTHETICS_MONITORS_EMBEDDABLE, - buildEmbeddable: async ({ initialState, finalizeApi, linkToContainerState }) => { + buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi }) => { const [coreStart, pluginStart] = await getStartServices(); const titleManager = initializeTitleManager(initialState); @@ -73,7 +73,7 @@ export const getMonitorsEmbeddableFactory = ( }); const view$ = new BehaviorSubject(initialState.view); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge(titleManager.anyStateChange$, filters$, view$).pipe( map(() => undefined) ), @@ -99,7 +99,7 @@ export const getMonitorsEmbeddableFactory = ( const api = finalizeApi({ ...titleManager.api, - ...containerStateApi, + ...stateApi, defaultTitle$, getTypeDisplayName: () => i18n.translate('xpack.synthetics.editSloOverviewEmbeddableTitle.typeDisplayName', { diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx index 31e20bd17ca9f..98a5793df9ac8 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx @@ -65,7 +65,7 @@ export const getStatsOverviewEmbeddableFactory = ( initializeDrilldownsManager, initialState, finalizeApi, - linkToContainerState, + initializeStateApi, }) => { const [coreStart, pluginStart] = await getStartServices(); @@ -81,7 +81,7 @@ export const getStatsOverviewEmbeddableFactory = ( const drilldownsManager = await initializeDrilldownsManager(uuid, initialState); - const containerStateApi = linkToContainerState({ + const stateApi = initializeStateApi({ anyStateChange$: merge( titleManager.anyStateChange$, filters$, @@ -110,7 +110,7 @@ export const getStatsOverviewEmbeddableFactory = ( const api = finalizeApi({ ...titleManager.api, ...drilldownsManager.api, - ...containerStateApi, + ...stateApi, supportedTriggers: () => SYNTHETICS_STATS_SUPPORTED_TRIGGERS, defaultTitle$, getTypeDisplayName: () => From 7e6731e55e50c4ec5804a481c59aa90a41dcafba Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 10 Apr 2026 13:39:13 -0400 Subject: [PATCH 05/10] fix macroscope comment --- .../single_metric_viewer_embeddable_factory.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx index 6b6a3c5037e11..c1f0c2238e0a2 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/single_metric_viewer/single_metric_viewer_embeddable_factory.tsx @@ -46,7 +46,7 @@ export const getSingleMetricViewerEmbeddableFactory = ( > = { type: ANOMALY_SINGLE_METRIC_VIEWER_EMBEDDABLE_TYPE, buildEmbeddable: async ({ initialState, finalizeApi, initializeStateApi, uuid, parentApi }) => { - const services = await getServices(getStartServices); + const services = await getServices(getStartServices, usageCollection); const subscriptions = new Subscription(); const titleManager = initializeTitleManager(initialState); const timeRangeManager = initializeTimeRangeManager(initialState); From 3dd5d97fa2e3d77d6c2be90826928dfb519f785f Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 10 Apr 2026 14:43:43 -0400 Subject: [PATCH 06/10] reinitialize maps cross panel actions, fix conflict resolution --- .../react_embeddable/initialize_cross_panel_actions.ts | 6 +++--- .../maps/public/react_embeddable/map_react_embeddable.tsx | 1 + .../embeddable/slo/overview/slo_embeddable_factory.tsx | 3 ++- 3 files changed, 6 insertions(+), 4 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 43c49a353bdd2..bd3b84a49fe76 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 @@ -226,9 +226,9 @@ export function initializeCrossPanelActions({ anyStateChange$: merge(isMovementSynchronized$, isFilterByMapExtent$).pipe( map(() => undefined) ), - reinitializeState: (lastSaved: MapEmbeddableState) => { - setIsMovementSynchronized(lastSaved.isMovementSynchronized); - setIsFilterByMapExtent(lastSaved.filterByMapExtent); + reinitializeState: (nextState?: MapEmbeddableState) => { + setIsMovementSynchronized(nextState?.isMovementSynchronized); + setIsFilterByMapExtent(nextState?.filterByMapExtent); }, 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 92d50ffdad9d3..1dbdd54a2e890 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 @@ -143,6 +143,7 @@ export const mapEmbeddableFactory: EmbeddableFactory }, applySerializedState: async (nextState) => { drilldownsManager.reinitializeState(nextState ?? {}); + crossPanelActions.reinitializeState(nextState); timeRangeManager.reinitializeState(nextState); titleManager.reinitializeState(nextState); diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx index 3ec1468e16209..5d918681e7905 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/overview/slo_embeddable_factory.tsx @@ -55,9 +55,10 @@ export const getOverviewEmbeddableFactory = ({ type: SLO_OVERVIEW_EMBEDDABLE_ID, buildEmbeddable: async ({ initializeDrilldownsManager, + initializeStateApi, initialState, finalizeApi, - initializeStateApi, + uuid, }) => { const deps = { ...coreStart, ...pluginsStart }; const state = initialState; From 79bad0dacbb7bfbe6978dbbc6b9fe1ed96b5b02a Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 10 Apr 2026 15:34:12 -0400 Subject: [PATCH 07/10] move initialize_state_api into embeddable plugin --- packages/kbn-optimizer/limits.yml | 2 +- .../presentation_publishing/index.ts | 5 +---- .../state_manager/index.ts | 2 +- .../initialize_state_api.ts} | 21 +++++++++++-------- .../react_embeddable_renderer.tsx | 3 ++- 5 files changed, 17 insertions(+), 16 deletions(-) rename src/platform/{packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts => plugins/shared/embeddable/public/react_embeddable_system/initialize_state_api.ts} (78%) diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index 9191bc6fb46ec..4ba4bc5bc2b49 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -50,7 +50,7 @@ pageLoadAssetSize: elasticAssistant: 301540 elasticAssistantSharedState: 4881 elasticConsole: 4451 - embeddable: 16634 + embeddable: 19659 embeddableAlertsTable: 6524 enterpriseSearch: 37565 entityStore: 9718 diff --git a/src/platform/packages/shared/presentation/presentation_publishing/index.ts b/src/platform/packages/shared/presentation/presentation_publishing/index.ts index 3e438776cfdbd..96ca82d2b32c5 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/index.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/index.ts @@ -13,6 +13,7 @@ export { type ComparatorFunction, type StateComparators, type WithAllKeys, + type StateManager, runComparator, areComparatorsEqual, diffComparators, @@ -208,10 +209,6 @@ export { } from './interfaces/containers/child_state'; export { childrenUnsavedChanges$ } from './interfaces/containers/container_state/children_unsaved_changes'; -export { - initializeStateApi, - type ContainerStateManagerInitializer, -} from './interfaces/containers/container_state/link_to_container_state'; export { apiCanDuplicatePanels, diff --git a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/index.ts b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/index.ts index 415cc2b8efcf1..c5dd6c316ac6e 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/state_manager/index.ts +++ b/src/platform/packages/shared/presentation/presentation_publishing/state_manager/index.ts @@ -10,4 +10,4 @@ export { shouldLogStateDiff, logStateDiff } from './state_diff_logger'; export { areComparatorsEqual, diffComparators, runComparator } from './state_comparators'; export { initializeStateManager } from './state_manager'; -export type { ComparatorFunction, StateComparators, WithAllKeys } from './types'; +export type { ComparatorFunction, StateComparators, WithAllKeys, StateManager } from './types'; diff --git a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/initialize_state_api.ts similarity index 78% rename from src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts rename to src/platform/plugins/shared/embeddable/public/react_embeddable_system/initialize_state_api.ts index ab2a6ab649131..a60d013a4a777 100644 --- a/src/platform/packages/shared/presentation/presentation_publishing/interfaces/containers/container_state/link_to_container_state.ts +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/initialize_state_api.ts @@ -7,16 +7,19 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { + apiHasLastSavedChildState, + areComparatorsEqual, + getTitle, + type HasParentApi, + type HasSerializableState, + type HasUniqueId, + type PresentationContainer, + type PublishesUnsavedChanges, + type StateComparators, + type StateManager, +} from '@kbn/presentation-publishing'; import { combineLatestWith, debounceTime, map, of } from 'rxjs'; -import { type StateComparators, areComparatorsEqual } from '../../../state_manager'; -import type { StateManager } from '../../../state_manager/types'; -import type { HasParentApi } from '../../has_parent_api'; -import type { HasSerializableState } from '../../has_serializable_state'; -import type { HasUniqueId } from '../../has_uuid'; -import type { PublishesUnsavedChanges } from '../../publishes_unsaved_changes'; -import { getTitle } from '../../titles/publishes_title'; -import { apiHasLastSavedChildState } from '../last_saved_child_state'; -import type { PresentationContainer } from '../presentation_container'; const UNSAVED_CHANGES_DEBOUNCE = 100; diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index c3a3540ebbea4..b6991e8801694 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -10,7 +10,7 @@ import type { PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; import { PresentationPanel } from '@kbn/presentation-panel-plugin/public'; import type { HasPanelCapabilities, HasSerializedChildState } from '@kbn/presentation-publishing'; -import { apiIsPresentationContainer, initializeStateApi } from '@kbn/presentation-publishing'; +import { apiIsPresentationContainer } from '@kbn/presentation-publishing'; import React, { useImperativeHandle, useMemo, useRef } from 'react'; import { BehaviorSubject } from 'rxjs'; import { v4 as generateId } from 'uuid'; @@ -18,6 +18,7 @@ import type { SerializedDrilldowns } from '../../server'; import { PhaseTracker } from './phase_tracker'; import { getReactEmbeddableFactory } from './react_embeddable_registry'; import type { DefaultEmbeddableApi, EmbeddableApiRegistration } from './types'; +import { initializeStateApi } from './initialize_state_api'; /** * Renders a component from the React Embeddable registry into a Presentation Panel. From d53c3bc1114a6d73ee8546786c94983ae174b9b0 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Fri, 10 Apr 2026 15:57:37 -0400 Subject: [PATCH 08/10] fix jest tests --- .../public/factories/alerts_table_embeddable_factory.test.tsx | 2 ++ .../anomaly_swimlane_embeddable_factory.test.tsx | 1 + 2 files changed, 3 insertions(+) diff --git a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.test.tsx b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.test.tsx index bbb0cc085cd52..cecd3752135c2 100644 --- a/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.test.tsx +++ b/x-pack/platform/plugins/shared/embeddable_alerts_table/public/factories/alerts_table_embeddable_factory.test.tsx @@ -17,6 +17,7 @@ import { getAlertsTableEmbeddableFactory } from './alerts_table_embeddable_facto import { PERSISTED_TABLE_CONFIG_KEY_PREFIX } from '../constants'; import type { InternalRuleType } from '@kbn/response-ops-rules-apis/apis/get_internal_rule_types'; import { getInternalRuleTypes } from '@kbn/response-ops-rules-apis/apis/get_internal_rule_types'; +import { getMockinitializeStateApi } from '@kbn/embeddable-plugin/public/mocks'; const core = coreMock.createStart(); const mockPresentationContainer = getMockPresentationContainer(); @@ -45,6 +46,7 @@ describe('getEmbeddableAlertsTableFactory', () => { ); const embeddableParams: Parameters[0] = { initializeDrilldownsManager: jest.fn(), + initializeStateApi: getMockinitializeStateApi(factory), initialState: { time_range: { from: '2025-01-01T00:00:00.000Z', diff --git a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx index 03f2c5b1142c5..9faafa701d471 100644 --- a/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx +++ b/x-pack/platform/plugins/shared/ml/public/embeddables/anomaly_swimlane/anomaly_swimlane_embeddable_factory.test.tsx @@ -88,6 +88,7 @@ describe('getAnomalySwimLaneEmbeddableFactory', () => { }; const { api, Component } = await factory.buildEmbeddable({ initializeDrilldownsManager: jest.fn(), + initializeStateApi: jest.fn(), initialState: { swimlaneType: 'viewBy', jobIds: ['my-job'], From 19743f6633b5ed5b2e2c0bec3a41e30e288ddf8a Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 13 Apr 2026 12:23:32 -0400 Subject: [PATCH 09/10] fix type import --- .../shared/embeddable/public/react_embeddable_system/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts index 7090827fb2208..96166e2919287 100644 --- a/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts +++ b/src/platform/plugins/shared/embeddable/public/react_embeddable_system/types.ts @@ -14,11 +14,11 @@ import type { HasType, PublishesPhaseEvents, PublishesUnsavedChanges, - ContainerStateManagerInitializer, } from '@kbn/presentation-publishing'; import type React from 'react'; import type { initializeDrilldownsManager } from '../drilldowns/drilldowns_manager'; import type { SerializedDrilldowns } from '../../server'; +import type { ContainerStateManagerInitializer } from './initialize_state_api'; /** * The default embeddable API that all Embeddables must implement. From a5e97654742099a8617231e5d8a45e34c6c8bab0 Mon Sep 17 00:00:00 2001 From: Devon Thomson Date: Mon, 13 Apr 2026 14:49:08 -0400 Subject: [PATCH 10/10] restore AI removed UUIDs. --- .../slo/burn_rate/burn_rate_react_embeddable_factory.tsx | 3 ++- .../stats_overview/stats_overview_embeddable_factory.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx index 31c5dd26733bb..0a726f3d611dd 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/burn_rate_react_embeddable_factory.tsx @@ -41,8 +41,9 @@ export const getBurnRateEmbeddableFactory = ({ const factory: EmbeddableFactory = { type: SLO_BURN_RATE_EMBEDDABLE_ID, buildEmbeddable: async ({ - initialState, + uuid, finalizeApi, + initialState, initializeStateApi, initializeDrilldownsManager, }) => { diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx index 98a5793df9ac8..6ebbc9e554422 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/embeddables/stats_overview/stats_overview_embeddable_factory.tsx @@ -63,9 +63,10 @@ export const getStatsOverviewEmbeddableFactory = ( type: SYNTHETICS_STATS_OVERVIEW_EMBEDDABLE, buildEmbeddable: async ({ initializeDrilldownsManager, + initializeStateApi, initialState, finalizeApi, - initializeStateApi, + uuid, }) => { const [coreStart, pluginStart] = await getStartServices();