mirror of
https://github.com/elastic/kibana.git
synced 2025-06-28 03:01:21 -04:00
Closes https://github.com/elastic/kibana/issues/205531 Closes #219877. Closes https://github.com/elastic/kibana/issues/213153 Closes https://github.com/elastic/kibana/issues/150920 Closes https://github.com/elastic/kibana/issues/203130 ### Overview The embeddable framework has two types of state: `SerializedState` and `RuntimeState`. `SerializedState` is the form of the state when saved into a Dashboard saved object. I.e. the References are extracted, and state saved externally (by reference) is removed. In contrast `RuntimeState` is an exact snapshot of the state used by the embeddable to render. <b>Exposing SerializedState and RuntimeState was a mistake</b> that caused numerous regressions and architectural complexities. This PR simplifies the embeddable framework by only exposing `SerializedState`. `RuntimeState` stays localized to the embeddable implementation and is never leaked to the embeddable framework. ### Whats changed * `ReactEmbeddableFactory<SerializedState, RuntimeState, Api>` => `EmbeddableFactory<SerializedState, Api>` * `deserializeState` removed from embeddable factory. Instead, `SerializedState` is passed directly into `buildEmbeddable`. * `buildEmbeddable` parameter `buildApi` replaced with `finalizeApi`. `buildApi({ api, comparators })` => `finalizeApi(api)`. * The embeddable framework previously used its knowledge of `RuntimeState` to setup and monitor unsaved changes. Now, unsaved changes setup is pushed down to the embeddable implementation since the embeddable framework no longer has knowledge of embeddable RuntimeState. ### Reviewer instructions <b>Please prioritize reviews.</b> This is a large effort from our team and is blocking many other initiatives. Getting this merged is a top priority. This is a large change that would best be reviewed by manually testing the changes * adding/editing your embeddable types * Ensuring dashboard shows unsaved changes as expected * Ensuring dashboard resets unsaved changes as expected * Ensuring dashboard does not show unsaved changes after save and reset * Returning to a dashboard with unsaved changes renders embeddables with those unsaved changes --------- Co-authored-by: Hannah Mudge <Heenawter@users.noreply.github.com> Co-authored-by: Nathan Reese <reese.nathan@elastic.co> Co-authored-by: Nick Peihl <nick.peihl@elastic.co> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Catherine Liu <catherine.liu@elastic.co> Co-authored-by: Ola Pawlus <98127445+olapawlus@users.noreply.github.com>
131 lines
3.9 KiB
TypeScript
131 lines
3.9 KiB
TypeScript
/*
|
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
* or more contributor license agreements. Licensed under the "Elastic License
|
|
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
|
|
* Public License v 1"; you may not use this file except in compliance with, at
|
|
* your election, the "Elastic License 2.0", the "GNU Affero General Public
|
|
* License v3.0 only", or the "Server Side Public License, v 1".
|
|
*/
|
|
|
|
import React, { useMemo, useState } from 'react';
|
|
|
|
import { EmbeddableRenderer } from '@kbn/embeddable-plugin/public';
|
|
import {
|
|
EuiCodeBlock,
|
|
EuiFlexGroup,
|
|
EuiFlexItem,
|
|
EuiSpacer,
|
|
EuiSuperDatePicker,
|
|
EuiSwitch,
|
|
EuiText,
|
|
OnTimeChangeProps,
|
|
} from '@elastic/eui';
|
|
import { BehaviorSubject, Subject } from 'rxjs';
|
|
import { TimeRange } from '@kbn/es-query';
|
|
import { useBatchedOptionalPublishingSubjects } from '@kbn/presentation-publishing';
|
|
import { SearchEmbeddableRenderer } from '../react_embeddables/search/search_embeddable_renderer';
|
|
import { SEARCH_EMBEDDABLE_TYPE } from '../react_embeddables/search/constants';
|
|
import type { SearchApi, SearchSerializedState } from '../react_embeddables/search/types';
|
|
|
|
export const RenderExamples = () => {
|
|
const parentApi = useMemo(() => {
|
|
return {
|
|
reload$: new Subject<void>(),
|
|
getSerializedStateForChild: () => ({
|
|
rawState: {
|
|
timeRange: undefined,
|
|
},
|
|
}),
|
|
timeRange$: new BehaviorSubject<TimeRange>({
|
|
from: 'now-24h',
|
|
to: 'now',
|
|
}),
|
|
};
|
|
// only run onMount
|
|
}, []);
|
|
|
|
const [api, setApi] = useState<SearchApi | null>(null);
|
|
const [hidePanelChrome, setHidePanelChrome] = useState<boolean>(false);
|
|
const [dataLoading, timeRange] = useBatchedOptionalPublishingSubjects(
|
|
api?.dataLoading$,
|
|
parentApi.timeRange$
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<EuiSuperDatePicker
|
|
isLoading={dataLoading ? dataLoading : false}
|
|
start={timeRange.from}
|
|
end={timeRange.to}
|
|
onTimeChange={({ start, end }: OnTimeChangeProps) => {
|
|
parentApi.timeRange$.next({
|
|
from: start,
|
|
to: end,
|
|
});
|
|
}}
|
|
onRefresh={() => {
|
|
parentApi.reload$.next();
|
|
}}
|
|
/>
|
|
|
|
<EuiSpacer size="s" />
|
|
|
|
<EuiFlexGroup>
|
|
<EuiFlexItem>
|
|
<EuiText>
|
|
<p>
|
|
Use <strong>EmbeddableRenderer</strong> to render embeddables.
|
|
</p>
|
|
</EuiText>
|
|
|
|
<EuiCodeBlock language="jsx" fontSize="m" paddingSize="m">
|
|
{`<EmbeddableRenderer<State, Api>
|
|
type={SEARCH_EMBEDDABLE_TYPE}
|
|
getParentApi={() => parentApi}
|
|
onApiAvailable={(newApi) => {
|
|
setApi(newApi);
|
|
}}
|
|
hidePanelChrome={hidePanelChrome}
|
|
/>`}
|
|
</EuiCodeBlock>
|
|
|
|
<EuiSpacer size="s" />
|
|
|
|
<EuiSwitch
|
|
label="Set hidePanelChrome to render embeddable without Panel wrapper."
|
|
checked={hidePanelChrome}
|
|
onChange={(e) => setHidePanelChrome(e.target.checked)}
|
|
/>
|
|
|
|
<EuiSpacer size="s" />
|
|
|
|
<EmbeddableRenderer<SearchSerializedState, SearchApi>
|
|
key={hidePanelChrome ? 'hideChrome' : 'showChrome'}
|
|
type={SEARCH_EMBEDDABLE_TYPE}
|
|
getParentApi={() => parentApi}
|
|
onApiAvailable={(newApi) => {
|
|
setApi(newApi);
|
|
}}
|
|
hidePanelChrome={hidePanelChrome}
|
|
/>
|
|
</EuiFlexItem>
|
|
|
|
<EuiFlexItem>
|
|
<EuiText>
|
|
<p>To avoid leaking embeddable details, wrap EmbeddableRenderer in a component.</p>
|
|
</EuiText>
|
|
|
|
<EuiCodeBlock language="jsx" fontSize="m" paddingSize="m">
|
|
{`<SearchEmbeddableRenderer
|
|
timeRange={timeRange}
|
|
/>`}
|
|
</EuiCodeBlock>
|
|
|
|
<EuiSpacer size="s" />
|
|
|
|
<SearchEmbeddableRenderer timeRange={timeRange} />
|
|
</EuiFlexItem>
|
|
</EuiFlexGroup>
|
|
</div>
|
|
);
|
|
};
|