mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Canvas add from library react embeddables (#183089)
Fixes #182619 Add support for React embeddables in the Canvas Add from Library flyout. I tested this against the [React Map embeddable PR](https://github.com/elastic/kibana/pull/178158).
This commit is contained in:
parent
fef94d7d34
commit
e5ff8743d1
3 changed files with 104 additions and 34 deletions
|
@ -25,6 +25,7 @@ export {
|
|||
EmbeddableStateTransfer,
|
||||
ErrorEmbeddable,
|
||||
genericEmbeddableInputIsEqual,
|
||||
getReactEmbeddableSavedObjects,
|
||||
isContextMenuTriggerContext,
|
||||
isEmbeddable,
|
||||
isErrorEmbeddable,
|
||||
|
@ -79,6 +80,7 @@ export type {
|
|||
PanelState,
|
||||
PropertySpec,
|
||||
RangeSelectContext,
|
||||
ReactEmbeddableSavedObject,
|
||||
ReferenceOrValueEmbeddable,
|
||||
SavedObjectEmbeddableInput,
|
||||
SelfStyledEmbeddable,
|
||||
|
|
|
@ -46,30 +46,39 @@ const renderReactEmbeddable = ({
|
|||
input,
|
||||
container,
|
||||
handlers,
|
||||
core,
|
||||
}: {
|
||||
type: string;
|
||||
uuid: string;
|
||||
input: EmbeddableInput;
|
||||
container: CanvasContainerApi;
|
||||
handlers: RendererHandlers;
|
||||
core: CoreStart;
|
||||
}) => {
|
||||
return (
|
||||
<ReactEmbeddableRenderer
|
||||
type={type}
|
||||
maybeId={uuid}
|
||||
parentApi={container as unknown as PresentationContainer}
|
||||
key={`${type}_${uuid}`}
|
||||
state={{ rawState: input }}
|
||||
onAnyStateChange={(newState) => {
|
||||
const newExpression = embeddableInputToExpression(
|
||||
newState.rawState as unknown as EmbeddableInput,
|
||||
type,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
if (newExpression) handlers.onEmbeddableInputChange(newExpression);
|
||||
}}
|
||||
/>
|
||||
<KibanaRenderContextProvider {...core}>
|
||||
<div
|
||||
className={CANVAS_EMBEDDABLE_CLASSNAME}
|
||||
style={{ width: '100%', height: '100%', cursor: 'auto' }}
|
||||
>
|
||||
<ReactEmbeddableRenderer
|
||||
type={type}
|
||||
maybeId={uuid}
|
||||
parentApi={container as unknown as PresentationContainer}
|
||||
key={`${type}_${uuid}`}
|
||||
state={{ rawState: input }}
|
||||
onAnyStateChange={(newState) => {
|
||||
const newExpression = embeddableInputToExpression(
|
||||
newState.rawState as unknown as EmbeddableInput,
|
||||
type,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
if (newExpression) handlers.onEmbeddableInputChange(newExpression);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</KibanaRenderContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -138,6 +147,7 @@ export const embeddableRendererFactory = (
|
|||
uuid: uniqueId,
|
||||
type: embeddableType,
|
||||
container: canvasApi,
|
||||
core,
|
||||
}),
|
||||
domNode,
|
||||
() => handlers.done()
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import React, { FC, useCallback, useMemo } from 'react';
|
||||
import { EuiFlyout, EuiFlyoutHeader, EuiFlyoutBody, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { SavedObjectFinder, SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public';
|
||||
import { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common';
|
||||
import {
|
||||
EmbeddableFactory,
|
||||
ReactEmbeddableSavedObject,
|
||||
getReactEmbeddableSavedObjects,
|
||||
} from '@kbn/embeddable-plugin/public';
|
||||
import { useEmbeddablesService, usePlatformService } from '../../services';
|
||||
|
||||
const strings = {
|
||||
|
@ -22,6 +28,14 @@ const strings = {
|
|||
defaultMessage: 'Add from library',
|
||||
}),
|
||||
};
|
||||
|
||||
interface LegacyFactoryMap {
|
||||
[key: string]: EmbeddableFactory;
|
||||
}
|
||||
interface FactoryMap<TSavedObjectAttributes extends FinderAttributes = FinderAttributes> {
|
||||
[key: string]: ReactEmbeddableSavedObject<TSavedObjectAttributes> & { type: string };
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
onClose: () => void;
|
||||
onSelect: (id: string, embeddableType: string, isByValueEnabled?: boolean) => void;
|
||||
|
@ -40,8 +54,67 @@ export const AddEmbeddableFlyout: FC<Props> = ({
|
|||
const { getEmbeddableFactories } = embeddablesService;
|
||||
const { getContentManagement, getUISettings } = platformService;
|
||||
|
||||
const legacyFactoriesBySavedObjectType: LegacyFactoryMap = useMemo(() => {
|
||||
return [...getEmbeddableFactories()]
|
||||
.filter(
|
||||
(embeddableFactory) =>
|
||||
Boolean(embeddableFactory.savedObjectMetaData?.type) && !embeddableFactory.isContainerType
|
||||
)
|
||||
.reduce((acc, factory) => {
|
||||
acc[factory.savedObjectMetaData!.type] = factory;
|
||||
return acc;
|
||||
}, {} as LegacyFactoryMap);
|
||||
}, [getEmbeddableFactories]);
|
||||
|
||||
const factoriesBySavedObjectType: FactoryMap = useMemo(() => {
|
||||
return [...getReactEmbeddableSavedObjects()]
|
||||
.filter(([type, embeddableFactory]) => {
|
||||
return Boolean(embeddableFactory.savedObjectMetaData?.type);
|
||||
})
|
||||
.reduce((acc, [type, factory]) => {
|
||||
acc[factory.savedObjectMetaData!.type] = {
|
||||
...factory,
|
||||
type,
|
||||
};
|
||||
return acc;
|
||||
}, {} as FactoryMap);
|
||||
}, []);
|
||||
|
||||
const metaData = useMemo(
|
||||
() =>
|
||||
[
|
||||
...Object.values(factoriesBySavedObjectType),
|
||||
...Object.values(legacyFactoriesBySavedObjectType),
|
||||
]
|
||||
.filter((factory) =>
|
||||
Boolean(
|
||||
factory.type !== 'links' && // Links panels only exist on Dashboards
|
||||
(isByValueEnabled || availableEmbeddables.includes(factory.type))
|
||||
)
|
||||
)
|
||||
.map((factory) => factory.savedObjectMetaData)
|
||||
.filter<SavedObjectMetaData<{}>>(function (
|
||||
maybeSavedObjectMetaData
|
||||
): maybeSavedObjectMetaData is SavedObjectMetaData<{}> {
|
||||
return maybeSavedObjectMetaData !== undefined;
|
||||
})
|
||||
.sort((a, b) => a.type.localeCompare(b.type)),
|
||||
[
|
||||
availableEmbeddables,
|
||||
factoriesBySavedObjectType,
|
||||
isByValueEnabled,
|
||||
legacyFactoriesBySavedObjectType,
|
||||
]
|
||||
);
|
||||
|
||||
const onAddPanel = useCallback(
|
||||
(id: string, savedObjectType: string) => {
|
||||
if (factoriesBySavedObjectType[savedObjectType]) {
|
||||
const factory = factoriesBySavedObjectType[savedObjectType];
|
||||
const { type } = factory;
|
||||
onSelect(id, type, isByValueEnabled);
|
||||
return;
|
||||
}
|
||||
const embeddableFactories = getEmbeddableFactories();
|
||||
// Find the embeddable type from the saved object type
|
||||
const found = Array.from(embeddableFactories).find((embeddableFactory) => {
|
||||
|
@ -55,24 +128,9 @@ export const AddEmbeddableFlyout: FC<Props> = ({
|
|||
|
||||
onSelect(id, foundEmbeddableType, isByValueEnabled);
|
||||
},
|
||||
[isByValueEnabled, getEmbeddableFactories, onSelect]
|
||||
[isByValueEnabled, getEmbeddableFactories, onSelect, factoriesBySavedObjectType]
|
||||
);
|
||||
|
||||
const embeddableFactories = getEmbeddableFactories();
|
||||
|
||||
const availableSavedObjects = Array.from(embeddableFactories)
|
||||
.filter(
|
||||
(factory) =>
|
||||
factory.type !== 'links' && // Links panels only exist on Dashboards
|
||||
(isByValueEnabled || availableEmbeddables.includes(factory.type))
|
||||
)
|
||||
.map((factory) => factory.savedObjectMetaData)
|
||||
.filter<SavedObjectMetaData<{}>>(function (
|
||||
maybeSavedObjectMetaData
|
||||
): maybeSavedObjectMetaData is SavedObjectMetaData<{}> {
|
||||
return maybeSavedObjectMetaData !== undefined;
|
||||
});
|
||||
|
||||
return (
|
||||
<EuiFlyout ownFocus onClose={onClose} data-test-subj="dashboardAddPanel">
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
|
@ -83,7 +141,7 @@ export const AddEmbeddableFlyout: FC<Props> = ({
|
|||
<EuiFlyoutBody>
|
||||
<SavedObjectFinder
|
||||
onChoose={onAddPanel}
|
||||
savedObjectMetaData={availableSavedObjects}
|
||||
savedObjectMetaData={metaData}
|
||||
showFilter={true}
|
||||
noItemsMessage={strings.getNoItemsText()}
|
||||
services={{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue