diff --git a/x-pack/plugins/cases/public/components/case_view/index.tsx b/x-pack/plugins/cases/public/components/case_view/index.tsx index df57e49073a604..38fadf6f04c5f8 100644 --- a/x-pack/plugins/cases/public/components/case_view/index.tsx +++ b/x-pack/plugins/cases/public/components/case_view/index.tsx @@ -43,6 +43,7 @@ import { useTimelineContext } from '../timeline_context/use_timeline_context'; import { CasesNavigation } from '../links'; import { OwnerProvider } from '../owner_context'; import { DoesNotExist } from './does_not_exist'; +import { CasesLensIntegration, CasesLensIntegrationProvider } from '../lens_context'; const gutterTimeline = '70px'; // seems to be a timeline reference from the original file export interface CaseViewComponentProps { @@ -60,6 +61,7 @@ export interface CaseViewComponentProps { } export interface CaseViewProps extends CaseViewComponentProps { + lensIntegration?: CasesLensIntegration; onCaseDataSuccess?: (data: Case) => void; timelineIntegration?: CasesTimelineIntegration; } @@ -485,6 +487,7 @@ export const CaseView = React.memo( caseId, configureCasesNavigation, getCaseDetailHrefWithCommentId, + lensIntegration, onCaseDataSuccess, onComponentInitialized, ruleDetailsNavigation, @@ -514,24 +517,26 @@ export const CaseView = React.memo( return ( data && ( - - - + + + + + ) ); diff --git a/x-pack/plugins/cases/public/components/lens_context/index.tsx b/x-pack/plugins/cases/public/components/lens_context/index.tsx new file mode 100644 index 00000000000000..311118d5f87241 --- /dev/null +++ b/x-pack/plugins/cases/public/components/lens_context/index.tsx @@ -0,0 +1,43 @@ +/* + * 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 React, { useState } from 'react'; +import { EuiMarkdownEditorUiPlugin, EuiMarkdownAstNodePosition } from '@elastic/eui'; +import { Plugin } from 'unified'; + +interface LensProcessingPluginRendererProps { + id: string | null; + title: string; + graphEventId?: string; + type: 'lens'; + [key: string]: string | null | undefined; +} + +export interface CasesLensIntegration { + editor_plugins: { + parsingPlugin: Plugin; + processingPluginRenderer: React.FC< + LensProcessingPluginRendererProps & { position: EuiMarkdownAstNodePosition } + >; + uiPlugin: EuiMarkdownEditorUiPlugin; + }; +} + +// This context is available to all children of the stateful_event component where the provider is currently set +export const CasesLensIntegrationContext = React.createContext(null); + +export const CasesLensIntegrationProvider: React.FC<{ + lensIntegration?: CasesLensIntegration; +}> = ({ children, lensIntegration }) => { + const [activeLensIntegration] = useState(lensIntegration ?? null); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/cases/public/components/lens_context/use_lens_context.ts b/x-pack/plugins/cases/public/components/lens_context/use_lens_context.ts new file mode 100644 index 00000000000000..8f3c3d4b67d60e --- /dev/null +++ b/x-pack/plugins/cases/public/components/lens_context/use_lens_context.ts @@ -0,0 +1,13 @@ +/* + * 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 { useContext } from 'react'; +import { CasesLensIntegrationContext } from '.'; + +export const useLensContext = () => { + return useContext(CasesLensIntegrationContext); +}; diff --git a/x-pack/plugins/cases/public/components/markdown_editor/types.ts b/x-pack/plugins/cases/public/components/markdown_editor/types.ts index bb932f2fcfe224..b38d6a820b502b 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/types.ts +++ b/x-pack/plugins/cases/public/components/markdown_editor/types.ts @@ -23,7 +23,7 @@ export type TemporaryProcessingPluginsType = [ [ typeof rehype2react, Parameters[0] & { - components: { a: FunctionComponent; timeline: unknown }; + components: { a: FunctionComponent; lens: unknown; timeline: unknown }; } ], ...PluggableList diff --git a/x-pack/plugins/cases/public/components/markdown_editor/use_plugins.ts b/x-pack/plugins/cases/public/components/markdown_editor/use_plugins.ts index e98af8bca8bcea..02c55b5111ab71 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/use_plugins.ts +++ b/x-pack/plugins/cases/public/components/markdown_editor/use_plugins.ts @@ -13,9 +13,11 @@ import { import { useMemo } from 'react'; import { useTimelineContext } from '../timeline_context/use_timeline_context'; import { TemporaryProcessingPluginsType } from './types'; +import { useLensContext } from '../lens_context/use_lens_context'; export const usePlugins = () => { const timelinePlugins = useTimelineContext()?.editor_plugins; + const lensPlugins = useLensContext()?.editor_plugins; return useMemo(() => { const uiPlugins = getDefaultEuiMarkdownUiPlugins(); @@ -31,10 +33,19 @@ export const usePlugins = () => { processingPlugins[1][1].components.timeline = timelinePlugins.processingPluginRenderer; } + if (lensPlugins) { + uiPlugins.push(lensPlugins.uiPlugin); + + parsingPlugins.push(lensPlugins.parsingPlugin); + + // This line of code is TS-compatible and it will break if [1][1] change in the future. + processingPlugins[1][1].components.lens = lensPlugins.processingPluginRenderer; + } + return { uiPlugins, parsingPlugins, processingPlugins, }; - }, [timelinePlugins]); + }, [lensPlugins, timelinePlugins]); }; diff --git a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx index b0f3ccb8c21ade..fa1414c089ff83 100644 --- a/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx +++ b/x-pack/plugins/security_solution/public/cases/components/case_view/index.tsx @@ -36,6 +36,7 @@ import { SEND_ALERT_TO_TIMELINE } from './translations'; import { useInsertTimeline } from '../use_insert_timeline'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; import * as timelineMarkdownPlugin from '../../../common/components/markdown_editor/plugins/timeline'; +import * as lensMarkdownPlugin from '../../../common/components/markdown_editor/plugins/lens'; interface Props { caseId: string; @@ -223,6 +224,13 @@ export const CaseView = React.memo(({ caseId, subCaseId, userCanCrud }: Props) = onClick: onConfigureCasesNavClick, }, getCaseDetailHrefWithCommentId, + lensIntegration: { + editor_plugins: { + parsingPlugin: lensMarkdownPlugin.parser, + processingPluginRenderer: lensMarkdownPlugin.renderer, + uiPlugin: lensMarkdownPlugin.plugin, + }, + }, onCaseDataSuccess, onComponentInitialized, ruleDetailsNavigation: {