Skip to content

Commit

Permalink
[RCA] Add from library to the investigation details page (elastic#192217
Browse files Browse the repository at this point in the history
)
  • Loading branch information
mgiota committed Sep 12, 2024
1 parent 94aac7a commit b02e1f3
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { METRIC_TYPE } from '@kbn/analytics';
import { apiHasType } from '@kbn/presentation-publishing';
import { Toast } from '@kbn/core/public';
import { PresentationContainer } from '@kbn/presentation-containers';
import { CanAddNewPanel } from '@kbn/presentation-containers';
import {
core,
embeddableStart,
Expand Down Expand Up @@ -85,7 +85,7 @@ export const AddPanelFlyout = ({
onAddPanel,
modalTitleId,
}: {
container: PresentationContainer;
container: CanAddNewPanel;
onAddPanel?: (id: string) => void;
modalTitleId?: string;
}) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { OverlayRef } from '@kbn/core/public';
import { EuiLoadingSpinner, htmlIdGenerator } from '@elastic/eui';
import { toMountPoint } from '@kbn/react-kibana-mount';

import { PresentationContainer } from '@kbn/presentation-containers';
import { CanAddNewPanel } from '@kbn/presentation-containers';
import { core } from '../kibana_services';

const LazyAddPanelFlyout = React.lazy(async () => {
Expand All @@ -28,7 +28,7 @@ export const openAddPanelFlyout = ({
onAddPanel,
onClose,
}: {
container: PresentationContainer;
container: CanAddNewPanel;
onAddPanel?: (id: string) => void;
onClose?: () => void;
}): OverlayRef => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@

import { IconType } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { PresentationContainer } from '@kbn/presentation-containers';
import { CanAddNewPanel } from '@kbn/presentation-containers';
import { FinderAttributes, SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common';
import { SavedObjectMetaData } from '@kbn/saved-objects-finder-plugin/public';

type SOToEmbeddable<TSavedObjectAttributes extends FinderAttributes = FinderAttributes> = (
container: PresentationContainer,
container: CanAddNewPanel,
savedObject: SavedObjectCommon<TSavedObjectAttributes>
) => void;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { EuiLoadingSpinner } from '@elastic/eui';
import { EuiLoadingSpinner, EuiFlexItem } from '@elastic/eui';
import { css } from '@emotion/css';
import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public';
import type { GlobalWidgetParameters } from '@kbn/investigate-plugin/public';
Expand All @@ -15,6 +15,8 @@ import { ErrorMessage } from '../../components/error_message';
import { useKibana } from '../../hooks/use_kibana';
import { Options } from '../register_items';

export const EMBEDDABLE_ITEM_TYPE = 'embeddable';

const embeddableClassName = css`
height: 100%;
> [data-shared-item] {
Expand All @@ -34,8 +36,9 @@ function ReactEmbeddable({ type, config, timeRange: { from, to }, savedObjectId
from,
to,
},
savedObjectId,
};
}, [config, from, to]);
}, [config, from, to, savedObjectId]);

const configWithOverridesRef = useRef(configWithOverrides);

Expand All @@ -48,18 +51,14 @@ function ReactEmbeddable({ type, config, timeRange: { from, to }, savedObjectId
}, []);

return (
<ReactEmbeddableRenderer
type={type}
getParentApi={() => api}
maybeId={savedObjectId}
onAnyStateChange={(state) => {
// console.log('onAnyStateChange', state);
}}
onApiAvailable={(childApi) => {
// console.log('onApiAvailable', childApi);
}}
hidePanelChrome
/>
<div className={embeddableClassName}>
<ReactEmbeddableRenderer
type={type}
getParentApi={() => api}
maybeId={savedObjectId}
hidePanelChrome
/>
</div>
);
}

Expand Down Expand Up @@ -166,7 +165,7 @@ export function registerEmbeddableItem({
services,
}: Options) {
investigate.registerItemDefinition<EmbeddableItemParams, {}>({
type: 'embeddable',
type: EMBEDDABLE_ITEM_TYPE,
generate: async (option: {
itemParams: EmbeddableItemParams;
globalParams: GlobalWidgetParameters;
Expand All @@ -184,7 +183,18 @@ export function registerEmbeddableItem({
timeRange: option.globalParams.timeRange,
};

return <EmbeddableWidget {...parameters} />;
return (
<EuiFlexItem
grow={true}
className={css`
> div {
height: 196px;
}
`}
>
<EmbeddableWidget {...parameters} />
</EuiFlexItem>
);
},
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { OverlayRef } from '@kbn/core/public';
import { v4 } from 'uuid';
import { openAddPanelFlyout } from '@kbn/embeddable-plugin/public';
import { i18n } from '@kbn/i18n';
import type { FinderAttributes } from '@kbn/saved-objects-finder-plugin/common';
import React, { useMemo, useRef } from 'react';
import { Item } from '@kbn/investigation-shared';
import { CanAddNewPanel } from '@kbn/presentation-containers';
import { EuiButtonEmpty } from '@elastic/eui';
import { EMBEDDABLE_ITEM_TYPE } from '../../../../items/embeddable_item/register_embeddable_item';
import { useKibana } from '../../../../hooks/use_kibana';
interface AddFromLibraryButtonProps {
onItemAdd: (item: Item) => Promise<void>;
}

type InvestigationContainer = CanAddNewPanel & {
addNewEmbeddable: (
type: string,
explicitInput: { savedObjectId: string },
attributes: FinderAttributes
) => Promise<{ id: string }>;
};

export function AddFromLibraryButton({ onItemAdd }: AddFromLibraryButtonProps) {
const {
dependencies: {
start: { contentManagement },
},
} = useKibana();

const panelRef = useRef<OverlayRef>();

const container = useMemo<
InvestigationContainer & {
addNewEmbeddable: (
type: string,
explicitInput: { savedObjectId: string },
attributes: FinderAttributes
) => Promise<{ id: string }>;
}
>(() => {
function addEmbeddable({
type,
title,
attributes,
savedObjectId,
}: {
type: string;
title: string;
attributes: Record<string, any>;
savedObjectId: string;
}) {
const embeddableItem = {
title,
type: EMBEDDABLE_ITEM_TYPE,
params: {
savedObjectId,
config: {},
type,
},
};
onItemAdd(embeddableItem).then(() => {
if (panelRef.current) {
panelRef.current.close();
}
});
}
return {
addNewPanel: async (panel, displaySuccessMessage) => {
const state = panel.initialState! as {
savedObjectId: string;
};
const savedObject = (await contentManagement.client.get({
contentTypeId: panel.panelType,
id: state.savedObjectId,
})) as { item: { attributes: { title: string } } };
addEmbeddable({
type: panel.panelType,
savedObjectId: state.savedObjectId,
attributes: {},
title: savedObject.item.attributes.title,
});

return undefined as any;
},
addNewEmbeddable: async (type, explicitInput, attributes) => {
addEmbeddable({
type,
title: attributes.title ?? '',
savedObjectId: explicitInput.savedObjectId,
attributes,
});
return { id: v4() };
},
};
}, [contentManagement.client, onItemAdd]);

return (
<EuiButtonEmpty
data-test-subj="investigateAppAddFromLibraryButtonImportFromLibraryButton"
iconType="importAction"
onClick={() => {
panelRef.current = openAddPanelFlyout({
container,
});

panelRef.current.onClose.then(() => {
panelRef.current = undefined;
});
}}
>
{i18n.translate('xpack.investigateApp.addFromLibraryButtonLabel', {
defaultMessage: 'Import from library',
})}
</EuiButtonEmpty>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { css } from '@emotion/css';
import { TextBasedLangEditor } from '@kbn/esql/public';
import { i18n } from '@kbn/i18n';
import React from 'react';
import { AddFromLibraryButton } from '../add_from_library_button';
import { useInvestigation } from '../../contexts/investigation_context';
import { EsqlWidgetPreview } from './esql_widget_preview';

Expand Down Expand Up @@ -64,7 +65,7 @@ export function AddInvestigationItem() {
</EuiFlexItem>
<EuiFlexItem grow={true}>
<EuiPanel color="subdued" hasShadow={false}>
<EuiFlexGroup direction="column" gutterSize="m">
<EuiFlexGroup gutterSize="m">
<EuiFlexItem>
<TextBasedLangEditor
query={query}
Expand All @@ -86,36 +87,44 @@ export function AddInvestigationItem() {
/>
</EuiFlexItem>

{!isPreviewOpen ? (
<EuiFlexGroup
direction="column"
alignItems="center"
gutterSize="l"
className={emptyPreview}
>
<EuiFlexItem grow={false}>
<EuiIcon type="image" size="xxl" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<p>
{i18n.translate(
'xpack.investigateApp.addObservationUI.p.selectADataSourceLabel',
{ defaultMessage: 'Select a data source to generate a preview chart' }
)}
</p>
</EuiFlexItem>
</EuiFlexGroup>
) : (
<EsqlWidgetPreview
esqlQuery={submittedQuery.esql}
timeRange={globalParams.timeRange}
<EuiFlexItem grow={false}>
<AddFromLibraryButton
onItemAdd={async (item) => {
resetState();
await addItem(item);
}}
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
{!isPreviewOpen ? (
<EuiFlexGroup
direction="column"
alignItems="center"
gutterSize="l"
className={emptyPreview}
>
<EuiFlexItem grow={false}>
<EuiIcon type="image" size="xxl" />
</EuiFlexItem>
<EuiFlexItem grow={false}>
<p>
{i18n.translate(
'xpack.investigateApp.addObservationUI.p.selectADataSourceLabel',
{ defaultMessage: 'Select a data source to generate a preview chart' }
)}
</p>
</EuiFlexItem>
</EuiFlexGroup>
) : (
<EsqlWidgetPreview
esqlQuery={submittedQuery.esql}
timeRange={globalParams.timeRange}
onItemAdd={async (item) => {
resetState();
await addItem(item);
}}
/>
)}
</EuiPanel>
</EuiFlexItem>
<EuiFlexGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
"@kbn/shared-ux-router",
"@kbn/investigation-shared",
"@kbn/core-security-common",
"@kbn/saved-objects-finder-plugin",
"@kbn/presentation-containers",
"@kbn/lens-embeddable-utils",
"@kbn/i18n-react",
],
Expand Down

0 comments on commit b02e1f3

Please sign in to comment.