From 245f010ac1038a18a801e18e096dde08bbdae095 Mon Sep 17 00:00:00 2001 From: Nick Peihl Date: Wed, 16 Apr 2025 11:13:04 -0400 Subject: [PATCH] [Serialized State Only] [SLO] Convert SLO Burn rate to serialized state only (#218461) _This PR does not need to be reviewed by external teams. This PR merges into a feature branch that Kibana presentation team is working on to convert the embeddable framework to only expose serialized state. Your team will be pinged for review once the work is complete and the final PR opens that merges the feature branch into main._ ## Summary Convert SLO burn rate to serialized state only ## Testing this PR Create an SLO using the "How to Test" section in the description of [this PR](https://github.com/elastic/kibana/pull/179147). --- .../burn_rate_react_embeddable_factory.tsx | 91 +++++++++++-------- .../public/embeddable/slo/burn_rate/types.ts | 2 +- .../create_burn_rate_panel_action.tsx | 2 +- 3 files changed, 53 insertions(+), 42 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 993f5b1577af..953f99bc58cc 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 @@ -4,23 +4,26 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; +import { EmbeddableFactory } from '@kbn/embeddable-plugin/public'; import { i18n } from '@kbn/i18n'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import { initializeUnsavedChanges } from '@kbn/presentation-containers'; import { fetch$, + initializeStateManager, initializeTitleManager, + titleComparators, useBatchedPublishingSubjects, } from '@kbn/presentation-publishing'; import { Router } from '@kbn/shared-ux-router'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { createBrowserHistory } from 'history'; import React, { useEffect } from 'react'; -import { BehaviorSubject, Subject } from 'rxjs'; +import { BehaviorSubject, Subject, merge } from 'rxjs'; import { CoreStart } from '@kbn/core-lifecycle-browser'; import { BurnRate } from './burn_rate'; import { SLO_BURN_RATE_EMBEDDABLE_ID } from './constants'; -import { BurnRateApi, SloBurnRateEmbeddableState } from './types'; +import { BurnRateApi, BurnRateCustomInput, SloBurnRateEmbeddableState } from './types'; import type { SLOPublicPluginsStart, SLORepositoryClient } from '../../../types'; import { PluginContext } from '../../../context/plugin_context'; @@ -38,46 +41,54 @@ export const getBurnRateEmbeddableFactory = ({ pluginsStart: SLOPublicPluginsStart; sloClient: SLORepositoryClient; }) => { - const factory: ReactEmbeddableFactory< - SloBurnRateEmbeddableState, - SloBurnRateEmbeddableState, - BurnRateApi - > = { + const factory: EmbeddableFactory = { type: SLO_BURN_RATE_EMBEDDABLE_ID, - deserializeState: (state) => { - return state.rawState as SloBurnRateEmbeddableState; - }, - buildEmbeddable: async (state, buildApi, uuid, parentApi) => { + buildEmbeddable: async ({ initialState, finalizeApi, uuid, parentApi }) => { const deps = { ...coreStart, ...pluginsStart }; - const titleManager = initializeTitleManager(state); + const titleManager = initializeTitleManager(initialState.rawState); const defaultTitle$ = new BehaviorSubject(getTitle()); - const sloId$ = new BehaviorSubject(state.sloId); - const sloInstanceId$ = new BehaviorSubject(state.sloInstanceId); - const duration$ = new BehaviorSubject(state.duration); - const reload$ = new Subject(); - - const api = buildApi( + const sloBurnRateManager = initializeStateManager( + initialState.rawState, { - ...titleManager.api, - defaultTitle$, - serializeState: () => { - return { - rawState: { - ...titleManager.serialize(), - sloId: sloId$.getValue(), - sloInstanceId: sloInstanceId$.getValue(), - duration: duration$.getValue(), - }, - }; - }, - }, - { - sloId: [sloId$, (value) => sloId$.next(value)], - sloInstanceId: [sloInstanceId$, (value) => sloInstanceId$.next(value)], - duration: [duration$, (value) => duration$.next(value)], - ...titleManager.comparators, + sloId: '', + sloInstanceId: '', + duration: '', } ); + const reload$ = new Subject(); + + function serializeState() { + return { + rawState: { + ...titleManager.getLatestState(), + ...sloBurnRateManager.getLatestState(), + }, + }; + } + + const unsavedChangesApi = initializeUnsavedChanges({ + uuid, + parentApi, + anyStateChange$: merge(titleManager.anyStateChange$, sloBurnRateManager.anyStateChange$), + serializeState, + getComparators: () => ({ + ...titleComparators, + sloId: 'referenceEquality', + sloInstanceId: 'referenceEquality', + duration: 'referenceEquality', + }), + onReset: (lastSaved) => { + sloBurnRateManager.reinitializeState(lastSaved?.rawState); + titleManager.reinitializeState(lastSaved?.rawState); + }, + }); + + const api = finalizeApi({ + ...titleManager.api, + ...unsavedChangesApi, + defaultTitle$, + serializeState, + }); const fetchSubscription = fetch$(api) .pipe() @@ -89,9 +100,9 @@ export const getBurnRateEmbeddableFactory = ({ api, Component: () => { const [sloId, sloInstanceId, duration] = useBatchedPublishingSubjects( - sloId$, - sloInstanceId$, - duration$ + sloBurnRateManager.api.sloId$, + sloBurnRateManager.api.sloInstanceId$, + sloBurnRateManager.api.duration$ ); useEffect(() => { diff --git a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/types.ts b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/types.ts index 0a8aeb066c76..2dff6cb9d5d7 100644 --- a/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/types.ts +++ b/x-pack/solutions/observability/plugins/slo/public/embeddable/slo/burn_rate/types.ts @@ -25,7 +25,7 @@ export interface EmbeddableProps { reloadSubject?: Subject; } -interface BurnRateCustomInput { +export interface BurnRateCustomInput { sloId: string; sloInstanceId: string; duration: string; diff --git a/x-pack/solutions/observability/plugins/slo/public/ui_actions/create_burn_rate_panel_action.tsx b/x-pack/solutions/observability/plugins/slo/public/ui_actions/create_burn_rate_panel_action.tsx index c55dd85aa702..a9f61e5a7a43 100644 --- a/x-pack/solutions/observability/plugins/slo/public/ui_actions/create_burn_rate_panel_action.tsx +++ b/x-pack/solutions/observability/plugins/slo/public/ui_actions/create_burn_rate_panel_action.tsx @@ -44,7 +44,7 @@ export function createBurnRatePanelAction( embeddable.addNewPanel( { panelType: SLO_BURN_RATE_EMBEDDABLE_ID, - initialState, + serializedState: { rawState: initialState }, }, true );