From 4069ba99061b1164e7012996e68d85b60e675ebe Mon Sep 17 00:00:00 2001 From: PhilippeOberti Date: Mon, 16 Sep 2024 10:54:52 -0500 Subject: [PATCH] wip --- .../kbn-expandable-flyout/src/context.tsx | 2 + .../kbn-expandable-flyout/src/provider.tsx | 5 + .../app/home/template_wrapper/index.tsx | 25 +- .../left/components/session_view.tsx | 49 ++-- .../components/session_preview_container.tsx | 4 +- .../document_details/session_view/content.tsx | 37 +++ .../document_details/session_view/context.tsx | 96 +++++++ .../document_details/session_view/header.tsx | 56 ++++ .../document_details/session_view/index.tsx | 90 ++++++ .../document_details/session_view/tabs.tsx | 58 ++++ .../session_view/tabs/alerts_tab.tsx | 121 ++++++++ .../session_view/tabs/metadata_tab.tsx | 40 +++ .../session_view/tabs/process_tab.tsx | 35 +++ .../document_details/session_view/test_ids.ts | 12 + .../shared/constants/panel_keys.ts | 1 + .../hooks/use_session_view_config.test.tsx} | 20 +- .../hooks/use_session_view_config.ts} | 12 +- .../security_solution/public/flyout/index.tsx | 12 + .../resolver/view/controls/show_panel.tsx | 2 +- .../tabs/session/use_session_view.tsx | 2 + x-pack/plugins/session_view/kibana.jsonc | 2 +- .../detail_panel_alert_tab/index.tsx | 2 + .../detail_panel_process_tab/index.tsx | 4 + .../public/components/process_tree/hooks.ts | 2 +- .../components/process_tree_node/index.tsx | 7 +- .../public/components/session_view/index.tsx | 264 +++++++++++------- .../session_view_detail_panel/index.tsx | 16 +- x-pack/plugins/session_view/public/index.ts | 5 + .../session_view/public/methods/index.tsx | 15 + x-pack/plugins/session_view/public/plugin.ts | 5 +- x-pack/plugins/session_view/public/types.ts | 4 + .../server/routes/process_events_route.ts | 42 ++- 32 files changed, 872 insertions(+), 175 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/content.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/context.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/header.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/index.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/alerts_tab.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/metadata_tab.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/process_tab.tsx create mode 100644 x-pack/plugins/security_solution/public/flyout/document_details/session_view/test_ids.ts rename x-pack/plugins/security_solution/public/flyout/document_details/{right/hooks/use_session_preview.test.tsx => shared/hooks/use_session_view_config.test.tsx} (79%) rename x-pack/plugins/security_solution/public/flyout/document_details/{right/hooks/use_session_preview.ts => shared/hooks/use_session_view_config.ts} (82%) diff --git a/packages/kbn-expandable-flyout/src/context.tsx b/packages/kbn-expandable-flyout/src/context.tsx index 65074a512ad8c..454cf1a5ec4a4 100644 --- a/packages/kbn-expandable-flyout/src/context.tsx +++ b/packages/kbn-expandable-flyout/src/context.tsx @@ -43,6 +43,8 @@ export const ExpandableFlyoutContextProvider = memo {children} diff --git a/packages/kbn-expandable-flyout/src/provider.tsx b/packages/kbn-expandable-flyout/src/provider.tsx index cad83bb0ee808..e01d91b6b4863 100644 --- a/packages/kbn-expandable-flyout/src/provider.tsx +++ b/packages/kbn-expandable-flyout/src/provider.tsx @@ -39,14 +39,17 @@ export const UrlSynchronizer = () => { ); useEffect(() => { + // console.log('useEffect urlKey', urlKey); if (!urlKey) { return; } const currentValue = urlStorage.get(urlKey); + // console.log('currentValue', currentValue); // Dispatch current value to redux store as it does not happen automatically if (currentValue) { + // console.log('dispatching urlChangedAction', currentValue, urlKey); dispatch( urlChangedAction({ ...currentValue, @@ -57,6 +60,7 @@ export const UrlSynchronizer = () => { } const subscription = urlStorage.change$(urlKey).subscribe((value) => { + // console.log('dispatching urlChangedAction inside subscription', value, urlKey); dispatch(urlChangedAction({ ...value, preview: value?.preview?.at(-1), id: urlKey })); }); @@ -91,6 +95,7 @@ export const ExpandableFlyoutProvider: FC { + // console.log('ExpandableFlyoutProvider urlKey', urlKey); return ( diff --git a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx index f547d128ab54b..51f756cfa8022 100644 --- a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx +++ b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx @@ -7,19 +7,18 @@ import React, { type ReactNode, useMemo } from 'react'; import styled from 'styled-components'; -import { EuiThemeProvider, useEuiTheme, type EuiThemeComputed } from '@elastic/eui'; +import { useEuiTheme, type EuiThemeComputed } from '@elastic/eui'; import { IS_DRAGGING_CLASS_NAME } from '@kbn/securitysolution-t-grid'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; import type { KibanaPageTemplateProps } from '@kbn/shared-ux-page-kibana-template'; import { ExpandableFlyoutProvider } from '@kbn/expandable-flyout'; import { URL_PARAM_KEY } from '../../../common/hooks/use_url_state'; -import { SecuritySolutionFlyout, TimelineFlyout } from '../../../flyout'; +import { SecuritySolutionFlyout } from '../../../flyout'; import { useSecuritySolutionNavigation } from '../../../common/components/navigation/use_security_solution_navigation'; import { TimelineId } from '../../../../common/types/timeline'; import { getTimelineShowStatusByIdSelector } from '../../../timelines/store/selectors'; import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; import { GlobalKQLHeader } from './global_kql_header'; -import { Timeline } from './timeline'; import { useShowTimeline } from '../../../common/utils/timeline/use_show_timeline'; import { useRouteSpy } from '../../../common/utils/route/use_route_spy'; import { SecurityPageName } from '../../types'; @@ -103,16 +102,16 @@ export const SecuritySolutionTemplateWrapper: React.FC - {isTimelineBottomBarVisible && ( - - - - - - - - - )} + {/* {isTimelineBottomBarVisible && (*/} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* )}*/} )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.tsx index 3b45cd71b0a6f..0de3d05d717c8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/session_view.tsx @@ -10,23 +10,22 @@ import React, { useCallback, useMemo } from 'react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { TableId } from '@kbn/securitysolution-data-table'; import { EuiPanel } from '@elastic/eui'; -import { - ANCESTOR_INDEX, - ENTRY_LEADER_ENTITY_ID, - ENTRY_LEADER_START, -} from '../../shared/constants/field_names'; -import { getField } from '../../shared/utils'; +import type { Process } from '@kbn/session-view-plugin/common'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { SESSION_VIEW_TEST_ID } from './test_ids'; import { isActiveTimeline } from '../../../../helpers'; import { useSourcererDataView } from '../../../../sourcerer/containers'; -import { DocumentDetailsPreviewPanelKey } from '../../shared/constants/panel_keys'; +import { + DocumentDetailsPreviewPanelKey, + DocumentDetailsSessionViewPanelKey, +} from '../../shared/constants/panel_keys'; import { useKibana } from '../../../../common/lib/kibana'; import { useDocumentDetailsContext } from '../../shared/context'; import { SourcererScopeName } from '../../../../sourcerer/store/model'; import { detectionsTimelineIds } from '../../../../timelines/containers/helpers'; import { ALERT_PREVIEW_BANNER } from '../../preview/constants'; import { useLicense } from '../../../../common/hooks/use_license'; -import { useSessionPreview } from '../../right/hooks/use_session_preview'; +import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config'; import { SessionViewNoDataMessage } from '../../shared/components/session_view_no_data_message'; import { DocumentEventTypes } from '../../../../common/lib/telemetry'; @@ -37,18 +36,14 @@ export const SESSION_VIEW_ID = 'session-view'; */ export const SessionView: FC = () => { const { sessionView, telemetry } = useKibana().services; - const { getFieldsData, indexName, scopeId, dataFormattedForFieldBrowser } = - useDocumentDetailsContext(); + const { getFieldsData, scopeId, dataFormattedForFieldBrowser } = useDocumentDetailsContext(); + + const { canReadPolicyManagement } = useUserPrivileges().endpointPrivileges; - const sessionViewConfig = useSessionPreview({ getFieldsData, dataFormattedForFieldBrowser }); + const sessionViewConfig = useSessionViewConfig({ getFieldsData, dataFormattedForFieldBrowser }); const isEnterprisePlus = useLicense().isEnterprise(); const isEnabled = sessionViewConfig && isEnterprisePlus; - const ancestorIndex = getField(getFieldsData(ANCESTOR_INDEX)); // e.g in case of alert, we want to grab it's origin index - const sessionEntityId = getField(getFieldsData(ENTRY_LEADER_ENTITY_ID)) || ''; - const sessionStartTime = getField(getFieldsData(ENTRY_LEADER_START)) || ''; - const index = ancestorIndex || indexName; - const sourcererScope = useMemo(() => { if (isActiveTimeline(scopeId)) { return SourcererScopeName.timeline; @@ -83,14 +78,30 @@ export const SessionView: FC = () => { [openPreviewPanel, eventDetailsIndex, scopeId, telemetry] ); + const openDetails = useCallback( + (selectedProcess: Process | null) => + openPreviewPanel({ + id: DocumentDetailsSessionViewPanelKey, + params: { + selectedProcess, + index: sessionViewConfig?.index, + sessionEntityId: sessionViewConfig?.sessionEntityId, + sessionStartTime: sessionViewConfig?.sessionStartTime, + investigatedAlertId: sessionViewConfig?.investigatedAlertId, + scopeId, + }, + }), + [openPreviewPanel, sessionViewConfig, scopeId] + ); + return isEnabled ? (
{sessionView.getSessionView({ - index, - sessionEntityId, - sessionStartTime, + ...sessionViewConfig, isFullScreen: true, loadAlertDetails: openAlertDetailsPreview, + openDetails: (selectedProcess: Process | null) => openDetails(selectedProcess), + canReadPolicyManagement, })}
) : ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx index 4098b35a0abfc..4072dfbf250f8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/session_preview_container.tsx @@ -13,7 +13,7 @@ import { useUiSetting$ } from '@kbn/kibana-react-plugin/public'; import { ENABLE_VISUALIZATIONS_IN_FLYOUT_SETTING } from '../../../../../common/constants'; import { useLicense } from '../../../../common/hooks/use_license'; import { SessionPreview } from './session_preview'; -import { useSessionPreview } from '../hooks/use_session_preview'; +import { useSessionViewConfig } from '../../shared/hooks/use_session_view_config'; import { useInvestigateInTimeline } from '../../../../detections/components/alerts_table/timeline_actions/use_investigate_in_timeline'; import { useDocumentDetailsContext } from '../../shared/context'; import { ALERTS_ACTIONS } from '../../../../common/lib/apm/user_actions'; @@ -47,7 +47,7 @@ export const SessionPreviewContainer: FC = () => { ); // decide whether to show the session view or not - const sessionViewConfig = useSessionPreview({ getFieldsData, dataFormattedForFieldBrowser }); + const sessionViewConfig = useSessionViewConfig({ getFieldsData, dataFormattedForFieldBrowser }); const isEnterprisePlus = useLicense().isEnterprise(); const isEnabled = sessionViewConfig && isEnterprisePlus; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/content.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/content.tsx new file mode 100644 index 0000000000000..8cb60ccc1a697 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/content.tsx @@ -0,0 +1,37 @@ +/* + * 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 { FC } from 'react'; +import React, { useMemo } from 'react'; +import type { SessionViewPanelPaths } from '.'; +import type { SessionViewPanelTabType } from './tabs'; +import { FlyoutBody } from '../../shared/components/flyout_body'; + +export interface PanelContentProps { + /** + * Id of the tab selected in the parent component to display its content + */ + selectedTabId: SessionViewPanelPaths; + /** + * Tabs display right below the flyout's header + */ + tabs: SessionViewPanelTabType[]; +} + +/** + * Document details expandable flyout right section, that will display the content + * of the overview, table and json tabs. + */ +export const PanelContent: FC = ({ selectedTabId, tabs }) => { + const selectedTabContent = useMemo(() => { + return tabs.find((tab) => tab.id === selectedTabId)?.content; + }, [selectedTabId, tabs]); + + return {selectedTabContent}; +}; + +PanelContent.displayName = 'PanelContent'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/context.tsx new file mode 100644 index 0000000000000..b1bdf26a2ca77 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/context.tsx @@ -0,0 +1,96 @@ +/* + * 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, { createContext, memo, useContext, useMemo } from 'react'; +import type { Process } from '@kbn/session-view-plugin/common'; +import { FlyoutError } from '../../shared/components/flyout_error'; +import type { SessionViewPanelProps } from '.'; + +export interface SessionViewPanelContext { + selectedProcess: Process | null; + index: string; + sessionEntityId: string; + sessionStartTime: string; + scopeId: string; + investigatedAlertId: string; +} + +export const SessionViewPanelContext = createContext( + undefined +); + +export type SessionViewPanelProviderProps = { + /** + * React components to render + */ + children: React.ReactNode; +} & Partial; + +export const SessionViewPanelProvider = memo( + ({ + selectedProcess, + index, + sessionEntityId, + sessionStartTime, + scopeId, + investigatedAlertId, + children, + }: SessionViewPanelProviderProps) => { + console.group('SessionViewPanelProvider'); + console.log('selectedProcess', selectedProcess); + console.log('index', index); + console.log('sessionEntityId', sessionEntityId); + console.log('sessionStartTime', sessionStartTime); + console.log('scopeId', scopeId); + console.log('investigatedAlertId', investigatedAlertId); + console.groupEnd(); + + const contextValue = useMemo( + () => + selectedProcess && + index && + sessionEntityId && + sessionStartTime && + scopeId && + investigatedAlertId + ? { + selectedProcess, + index, + sessionEntityId, + sessionStartTime, + scopeId, + investigatedAlertId, + } + : undefined, + [selectedProcess, index, sessionEntityId, sessionStartTime, scopeId] + ); + + if (!contextValue) { + return ; + } + + return ( + + {children} + + ); + } +); + +SessionViewPanelProvider.displayName = 'SessionViewPanelProvider'; + +export const useSessionViewPanelContext = (): SessionViewPanelContext => { + const contextValue = useContext(SessionViewPanelContext); + + if (!contextValue) { + throw new Error( + 'SessionViewPanelContext can only be used within SessionViewPanelContext provider' + ); + } + + return contextValue; +}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/header.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/header.tsx new file mode 100644 index 0000000000000..81574f16a18e1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/header.tsx @@ -0,0 +1,56 @@ +/* + * 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 { EuiFlyoutHeader } from '@elastic/eui'; +import { EuiTab } from '@elastic/eui'; +import type { FC } from 'react'; +import React, { memo } from 'react'; +import type { SessionViewPanelTabType } from './tabs'; +import type { SessionViewPanelPaths } from '.'; +import { FlyoutHeader } from '../../shared/components/flyout_header'; +import { FlyoutHeaderTabs } from '../../shared/components/flyout_header_tabs'; + +export interface PanelHeaderProps extends React.ComponentProps { + /** + * Id of the tab selected in the parent component to display its content + */ + selectedTabId: SessionViewPanelPaths; + /** + * Callback to set the selected tab id in the parent component + * @param selected + */ + setSelectedTabId: (selected: SessionViewPanelPaths) => void; + /** + * Tabs to display in the header + */ + tabs: SessionViewPanelTabType[]; +} + +export const PanelHeader: FC = memo( + ({ selectedTabId, setSelectedTabId, tabs, ...flyoutHeaderProps }) => { + const onSelectedTabChanged = (id: SessionViewPanelPaths) => setSelectedTabId(id); + + const renderTabs = tabs.map((tab, index) => ( + onSelectedTabChanged(tab.id)} + isSelected={tab.id === selectedTabId} + key={index} + data-test-subj={tab['data-test-subj']} + > + {tab.name} + + )); + + return ( + + {renderTabs} + + ); + } +); + +PanelHeader.displayName = 'PanelHeader'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/index.tsx new file mode 100644 index 0000000000000..177d3e72b7425 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/index.tsx @@ -0,0 +1,90 @@ +/* + * 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 { FC } from 'react'; +import { useCallback } from 'react'; +import React, { memo, useMemo } from 'react'; +import type { FlyoutPanelProps } from '@kbn/expandable-flyout'; +import { type PanelPath, useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import type { Process } from '@kbn/session-view-plugin/common'; +import { PanelContent } from './content'; +import { PanelHeader } from './header'; +import { useSessionViewPanelContext } from './context'; +import * as tabs from './tabs'; +import { DocumentDetailsSessionViewPanelKey } from '../shared/constants/panel_keys'; +import type { SessionViewPanelTabType } from './tabs'; + +export const allTabs = [tabs.processTab, tabs.metadataTab, tabs.alertsTab]; +export type SessionViewPanelPaths = 'process' | 'metadata' | 'alerts'; + +export interface SessionViewPanelProps extends FlyoutPanelProps { + key: typeof DocumentDetailsSessionViewPanelKey; + path?: PanelPath; + params: { + selectedProcess: Process | null; + index: string; + sessionEntityId: string; + sessionStartTime: string; + scopeId: string; + investigatedAlertId: string; + }; +} + +/** + * Displays node details panel for session view + */ +export const SessionViewPanel: FC> = memo(({ path }) => { + const { openPreviewPanel } = useExpandableFlyoutApi(); + const { selectedProcess, index, sessionEntityId, sessionStartTime, scopeId } = + useSessionViewPanelContext(); + + const selectedTabId = useMemo(() => { + // we use the value passed from the url and use it if it exists in the list of tabs to display + if (path) { + const selectedTab = allTabs.map((tab) => tab.id).find((tabId) => tabId === path.tab); + if (selectedTab) { + return selectedTab; + } + } + + // we default back to the first tab of the list of tabs to display in case everything else has failed + const defaultTab = allTabs[0].id; + return defaultTab; + }, [path]); + + const setSelectedTabId = useCallback( + (tabId: SessionViewPanelTabType['id']) => { + openPreviewPanel({ + id: DocumentDetailsSessionViewPanelKey, + path: { + tab: tabId, + }, + params: { + selectedProcess, + index, + sessionEntityId, + sessionStartTime, + scopeId, + }, + }); + }, + [index, openPreviewPanel, selectedProcess, sessionEntityId, sessionStartTime] + ); + + return ( + <> + + + + ); +}); + +SessionViewPanel.displayName = 'SessionViewPanel'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs.tsx new file mode 100644 index 0000000000000..e536448840837 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs.tsx @@ -0,0 +1,58 @@ +/* + * 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 { ReactElement } from 'react'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { ProcessTab } from './tabs/process_tab'; +import { MetadataTab } from './tabs/metadata_tab'; +import { AlertsTab } from './tabs/alerts_tab'; +import { ALERTS_TAB_TEST_ID, METADATA_TAB_TEST_ID, PROCESS_TAB_TEST_ID } from './test_ids'; +import type { SessionViewPanelPaths } from '.'; + +export interface SessionViewPanelTabType { + id: SessionViewPanelPaths; + name: ReactElement; + content: React.ReactElement; + 'data-test-subj': string; +} + +export const processTab: SessionViewPanelTabType = { + id: 'process', + 'data-test-subj': PROCESS_TAB_TEST_ID, + name: ( + + ), + content: , +}; + +export const metadataTab: SessionViewPanelTabType = { + id: 'metadata', + 'data-test-subj': METADATA_TAB_TEST_ID, + name: ( + + ), + content: , +}; + +export const alertsTab: SessionViewPanelTabType = { + id: 'alerts', + 'data-test-subj': ALERTS_TAB_TEST_ID, + name: ( + + ), + content: , +}; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/alerts_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/alerts_tab.tsx new file mode 100644 index 0000000000000..269d55a60ccfe --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/alerts_tab.tsx @@ -0,0 +1,121 @@ +/* + * 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, { memo, useCallback, useMemo } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { DetailPanelAlertTab, useFetchSessionViewAlerts } from '@kbn/session-view-plugin/public'; +import type { ProcessEvent } from '@kbn/session-view-plugin/common'; +import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { SESSION_VIEW_ID } from '../../left/components/session_view'; +import { + DocumentDetailsLeftPanelKey, + DocumentDetailsPreviewPanelKey, +} from '../../shared/constants/panel_keys'; +import { ALERT_PREVIEW_BANNER } from '../../preview/constants'; +import { useSessionViewPanelContext } from '../context'; + +/** + * + */ +export const AlertsTab = memo(() => { + const { index, sessionEntityId, sessionStartTime, scopeId } = useSessionViewPanelContext(); + const { + data: alertsData, + fetchNextPage: fetchNextPageAlerts, + isFetching: isFetchingAlerts, + hasNextPage: hasNextPageAlerts, + } = useFetchSessionViewAlerts(sessionEntityId, sessionStartTime, undefined); + + const alerts = useMemo(() => { + let events: ProcessEvent[] = []; + + if (alertsData) { + alertsData.pages.forEach((page) => { + events = events.concat(page.events); + }); + } + + return events; + }, [alertsData]); + + const { openPreviewPanel, openLeftPanel } = useExpandableFlyoutApi(); + const openAlertDetailsPreview = useCallback( + (eventId?: string, onClose?: () => void) => { + openPreviewPanel({ + id: DocumentDetailsPreviewPanelKey, + params: { + id: eventId, + indexName: index, + scopeId, + banner: ALERT_PREVIEW_BANNER, + isPreviewMode: true, + }, + }); + }, + [openPreviewPanel, index, scopeId] + ); + + const jumpToEvent = useCallback( + (event: ProcessEvent) => { + let jumpToEntityId = null; + let jumpToCursor = null; + if (event.process) { + const { entity_id: entityId } = event.process; + if (entityId !== sessionEntityId) { + const alert = event.kibana?.alert; + const cursor = alert ? alert?.original_time : event['@timestamp']; + + if (cursor) { + jumpToEntityId = entityId; + jumpToCursor = cursor; + } + } + } + + openLeftPanel({ + id: DocumentDetailsLeftPanelKey, + params: { + id: event.kibana?.alert?.uuid, + indexName: index, + scopeId, + jumpToEntityId, + jumpToCursor, + }, + path: { + tab: 'visualize', + subTab: SESSION_VIEW_ID, + }, + }); + }, + [index, openLeftPanel, scopeId, sessionEntityId] + ); + + return ( + + + + ); +}); + +AlertsTab.displayName = 'AlertsTab'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/metadata_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/metadata_tab.tsx new file mode 100644 index 0000000000000..f4212abc614b0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/metadata_tab.tsx @@ -0,0 +1,40 @@ +/* + * 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, { memo } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { DetailPanelMetadataTab } from '@kbn/session-view-plugin/public'; +import { useSessionViewPanelContext } from '../context'; + +/** + * + */ +export const MetadataTab = memo(() => { + const { selectedProcess } = useSessionViewPanelContext(); + + return ( + + + + ); +}); + +MetadataTab.displayName = 'MetadataTab'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/process_tab.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/process_tab.tsx new file mode 100644 index 0000000000000..3a16222821eb9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/tabs/process_tab.tsx @@ -0,0 +1,35 @@ +/* + * 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, { memo } from 'react'; +import { EuiPanel } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { DetailPanelProcessTab } from '@kbn/session-view-plugin/public'; +import { useSessionViewPanelContext } from '../context'; + +/** + * + */ +export const ProcessTab = memo(() => { + const { selectedProcess, index } = useSessionViewPanelContext(); + + return ( + + + + ); +}); + +ProcessTab.displayName = 'ProcessTab'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/session_view/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/test_ids.ts new file mode 100644 index 0000000000000..c9f19314ef450 --- /dev/null +++ b/x-pack/plugins/security_solution/public/flyout/document_details/session_view/test_ids.ts @@ -0,0 +1,12 @@ +/* + * 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 { PREFIX } from '../../shared/test_ids'; + +export const PROCESS_TAB_TEST_ID = `${PREFIX}ProcessTab` as const; +export const METADATA_TAB_TEST_ID = `${PREFIX}MetadataTab` as const; +export const ALERTS_TAB_TEST_ID = `${PREFIX}AlertsTab` as const; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/panel_keys.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/panel_keys.ts index fa40f1e0e6674..e68313ed6707e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/panel_keys.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/constants/panel_keys.ts @@ -12,3 +12,4 @@ export const DocumentDetailsPreviewPanelKey = 'document-details-preview' as cons export const DocumentDetailsIsolateHostPanelKey = 'document-details-isolate-host' as const; export const DocumentDetailsAlertReasonPanelKey = 'document-details-alert-reason' as const; export const DocumentDetailsAnalyzerPanelKey = 'document-details-analyzer-details' as const; +export const DocumentDetailsSessionViewPanelKey = 'document-details-sessions-view-details' as const; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.test.tsx similarity index 79% rename from x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.test.tsx rename to x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.test.tsx index 4e2e19c6b54fa..11cb97548e94c 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.test.tsx @@ -7,15 +7,15 @@ import type { RenderHookResult } from '@testing-library/react'; import { renderHook } from '@testing-library/react'; -import type { UseSessionPreviewParams } from './use_session_preview'; -import { useSessionPreview } from './use_session_preview'; +import type { UseSessionViewConfigParams } from './use_session_view_config'; +import { useSessionViewConfig } from './use_session_view_config'; import type { SessionViewConfig } from '@kbn/securitysolution-data-table/common/types'; -import type { GetFieldsData } from '../../shared/hooks/use_get_fields_data'; -import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_formatted_for_field_browser'; -import { mockFieldData, mockGetFieldsData } from '../../shared/mocks/mock_get_fields_data'; +import type { GetFieldsData } from './use_get_fields_data'; +import { mockDataFormattedForFieldBrowser } from '../mocks/mock_data_formatted_for_field_browser'; +import { mockFieldData, mockGetFieldsData } from '../mocks/mock_get_fields_data'; -describe('useSessionPreview', () => { - let hookResult: RenderHookResult; +describe('useSessionViewConfig', () => { + let hookResult: RenderHookResult; it(`should return a session view config object if alert ancestor index is available`, () => { const getFieldsData: GetFieldsData = (field: string) => { @@ -36,7 +36,7 @@ describe('useSessionPreview', () => { }, ]; - hookResult = renderHook((props: UseSessionPreviewParams) => useSessionPreview(props), { + hookResult = renderHook((props: UseSessionViewConfigParams) => useSessionViewConfig(props), { initialProps: { getFieldsData, dataFormattedForFieldBrowser, @@ -71,7 +71,7 @@ describe('useSessionPreview', () => { isObjectArray: false, }, ]; - hookResult = renderHook((props: UseSessionPreviewParams) => useSessionPreview(props), { + hookResult = renderHook((props: UseSessionViewConfigParams) => useSessionViewConfig(props), { initialProps: { getFieldsData: mockGetFieldsData, dataFormattedForFieldBrowser, @@ -91,7 +91,7 @@ describe('useSessionPreview', () => { it(`should return null if data isn't ready for session view`, () => { const getFieldsData: GetFieldsData = (field: string) => ''; - hookResult = renderHook((props: UseSessionPreviewParams) => useSessionPreview(props), { + hookResult = renderHook((props: UseSessionViewConfigParams) => useSessionViewConfig(props), { initialProps: { getFieldsData, dataFormattedForFieldBrowser: mockDataFormattedForFieldBrowser, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.ts similarity index 82% rename from x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.ts rename to x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.ts index 4b2132d265871..891b550c1aee8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_session_preview.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_session_view_config.ts @@ -7,11 +7,11 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import type { SessionViewConfig } from '@kbn/securitysolution-data-table/common/types'; -import type { GetFieldsData } from '../../shared/hooks/use_get_fields_data'; -import { getField } from '../../shared/utils'; -import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data'; +import type { GetFieldsData } from './use_get_fields_data'; +import { getField } from '../utils'; +import { useBasicDataFromDetailsData } from './use_basic_data_from_details_data'; -export interface UseSessionPreviewParams { +export interface UseSessionViewConfigParams { /** * Retrieves searchHit values for the provided field */ @@ -25,10 +25,10 @@ export interface UseSessionPreviewParams { /** * Hook that returns the session view configuration if the session view is available for the alert */ -export const useSessionPreview = ({ +export const useSessionViewConfig = ({ getFieldsData, dataFormattedForFieldBrowser, -}: UseSessionPreviewParams): SessionViewConfig | null => { +}: UseSessionViewConfigParams): SessionViewConfig | null => { const { indexName: _index, alertId: _id } = useBasicDataFromDetailsData( dataFormattedForFieldBrowser ); diff --git a/x-pack/plugins/security_solution/public/flyout/index.tsx b/x-pack/plugins/security_solution/public/flyout/index.tsx index ab5c874898ef0..a996d52f5fada 100644 --- a/x-pack/plugins/security_solution/public/flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/index.tsx @@ -8,6 +8,9 @@ import React, { memo, useCallback } from 'react'; import { ExpandableFlyout, type ExpandableFlyoutProps } from '@kbn/expandable-flyout'; import { useEuiTheme } from '@elastic/eui'; +import { SessionViewPanelProvider } from './document_details/session_view/context'; +import type { SessionViewPanelProps } from './document_details/session_view'; +import { SessionViewPanel } from './document_details/session_view'; import type { NetworkExpandableFlyoutProps } from './network_details'; import { Flyouts } from './document_details/shared/constants/flyouts'; import { @@ -17,6 +20,7 @@ import { DocumentDetailsPreviewPanelKey, DocumentDetailsAlertReasonPanelKey, DocumentDetailsAnalyzerPanelKey, + DocumentDetailsSessionViewPanelKey, } from './document_details/shared/constants/panel_keys'; import type { IsolateHostPanelProps } from './document_details/isolate_host'; import { IsolateHostPanel } from './document_details/isolate_host'; @@ -104,6 +108,14 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels'] ), }, + { + key: DocumentDetailsSessionViewPanelKey, + component: (props) => ( + + + + ), + }, { key: UserPanelKey, component: (props) => , diff --git a/x-pack/plugins/security_solution/public/resolver/view/controls/show_panel.tsx b/x-pack/plugins/security_solution/public/resolver/view/controls/show_panel.tsx index 72fa6c925f680..9a63ea3c233a1 100644 --- a/x-pack/plugins/security_solution/public/resolver/view/controls/show_panel.tsx +++ b/x-pack/plugins/security_solution/public/resolver/view/controls/show_panel.tsx @@ -27,7 +27,7 @@ export const ShowPanelButton = memo(({ showPanelOnClick }: { showPanelOnClick: ( title={showPanelButtonTitle} aria-label={showPanelButtonTitle} onClick={showPanelOnClick} - iconType={'eye'} + iconType={'expand'} $backgroundColor={colorMap.graphControlsBackground} $iconColor={colorMap.graphControls} $borderColor={colorMap.graphControlsBorderColor} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx index 67b9fd50eac22..44b2f22f3beb8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/session/use_session_view.tsx @@ -296,6 +296,8 @@ export const useSessionView = ({ scopeId, height }: { scopeId: string; height?: [openFlyout, alertsIndex, scopeId, telemetry] ); + console.log('sessionViewConfig', sessionViewConfig); + const sessionViewComponent = useMemo(() => { const sessionViewSearchBarHeight = 118; const heightMinusSearchBar = height ? height - sessionViewSearchBarHeight : undefined; diff --git a/x-pack/plugins/session_view/kibana.jsonc b/x-pack/plugins/session_view/kibana.jsonc index 3ec03862e6af9..f7f5e1b9a8c26 100644 --- a/x-pack/plugins/session_view/kibana.jsonc +++ b/x-pack/plugins/session_view/kibana.jsonc @@ -23,4 +23,4 @@ "esUiShared" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.tsx b/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.tsx index 37ed8dc8c835e..2d3c20f7756ad 100644 --- a/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.tsx +++ b/x-pack/plugins/session_view/public/components/detail_panel_alert_tab/index.tsx @@ -61,6 +61,8 @@ export const DetailPanelAlertTab = ({ ]; const investigatedAlert = useMemo(() => { + console.log('alerts', alerts); + console.log('investigatedAlertId', investigatedAlertId); return ( investigatedAlertId && alerts.find((event) => { diff --git a/x-pack/plugins/session_view/public/components/detail_panel_process_tab/index.tsx b/x-pack/plugins/session_view/public/components/detail_panel_process_tab/index.tsx index 13157546ccdb8..910f50a29337f 100644 --- a/x-pack/plugins/session_view/public/components/detail_panel_process_tab/index.tsx +++ b/x-pack/plugins/session_view/public/components/detail_panel_process_tab/index.tsx @@ -72,6 +72,10 @@ const LEADER_FIELD_PREFIX = [ * Detail panel in the session view. */ export const DetailPanelProcessTab = ({ selectedProcess, index }: DetailPanelProcessTabDeps) => { + // console.group('DetailPanelProcessTab'); + // console.log('selectedProcess', selectedProcess); + // console.log('index', index); + // console.groupEnd(); const styles = useStyles(); const processDetail = useMemo( diff --git a/x-pack/plugins/session_view/public/components/process_tree/hooks.ts b/x-pack/plugins/session_view/public/components/process_tree/hooks.ts index 867ae911843e9..0bd3c1622635b 100644 --- a/x-pack/plugins/session_view/public/components/process_tree/hooks.ts +++ b/x-pack/plugins/session_view/public/components/process_tree/hooks.ts @@ -241,7 +241,7 @@ export class ProcessImpl implements Process { const filtered = events.filter((processEvent) => { const action = processEvent?.event?.action; - return action?.includes('fork') || action?.includes('exec') || action?.includes('end'); + // return action?.includes('fork') || action?.includes('exec') || action?.includes('end'); }); // there are some anomalous processes which are omitting event.action diff --git a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx index a6201ea2ed504..f41ff15bb69ab 100644 --- a/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx +++ b/x-pack/plugins/session_view/public/components/process_tree_node/index.tsx @@ -316,7 +316,12 @@ export function ProcessTreeNode({ - + diff --git a/x-pack/plugins/session_view/public/components/session_view/index.tsx b/x-pack/plugins/session_view/public/components/session_view/index.tsx index bdb7e3ddc8c2b..80b2a68d2bdfd 100644 --- a/x-pack/plugins/session_view/public/components/session_view/index.tsx +++ b/x-pack/plugins/session_view/public/components/session_view/index.tsx @@ -62,7 +62,23 @@ export const SessionView = ({ loadAlertDetails, canReadPolicyManagement, trackEvent, + openDetails, }: SessionViewDeps & { trackEvent: (name: SessionViewTelemetryKey) => void }) => { + // console.group('SessionView'); + // console.log('index', index); + // console.log('sessionEntityId', sessionEntityId); + // console.log('sessionStartTime', sessionStartTime); + // // console.log('height', height); + // // console.log('isFullScreen', isFullScreen); + // console.log('jumpToEntityId', jumpToEntityId); + // console.log('jumpToCursor', jumpToCursor); + console.log('investigatedAlertId', investigatedAlertId); + // // console.log('loadAlertDetails', loadAlertDetails); + // console.log('canReadPolicyManagement', canReadPolicyManagement); + // // console.log('trackEvent', trackEvent); + // // console.log('openDetails', openDetails); + // console.groupEnd(); + // don't engage jumpTo if jumping to session leader. if (jumpToEntityId === sessionEntityId) { jumpToEntityId = undefined; @@ -114,9 +130,17 @@ export const SessionView = ({ return !!(!displayOptions?.verboseMode && searchQuery && searchResults?.length === 0); }, [displayOptions?.verboseMode, searchResults, searchQuery]); - const onProcessSelected = useCallback((process: Process | null) => { - setSelectedProcess(process); - }, []); + const onProcessSelected = useCallback( + (process: Process | null) => { + // console.log('onProcessSelected', process); + setSelectedProcess(process); + + if (openDetails) { + openDetails(process); + } + }, + [openDetails] + ); const onJumpToEvent = useCallback( (event: ProcessEvent) => { @@ -131,6 +155,7 @@ export const SessionView = ({ setCurrentJumpToCursor(cursor); } } + // console.log('onJumpToEvent setSelectedProcess to null'); setSelectedProcess(null); } }, @@ -261,6 +286,12 @@ export const SessionView = ({ } }, [isDetailOpen, trackEvent]); + const toggleDetailPanelInFlyout = useCallback(() => { + if (openDetails) { + openDetails(selectedProcess); + } + }, [openDetails, selectedProcess]); + const onShowAlertDetails = useCallback( (alertUuid: string) => { if (loadAlertDetails) { @@ -294,6 +325,86 @@ export const SessionView = ({ [displayOptions?.timestamp, displayOptions?.verboseMode, setDisplayOptions, trackEvent] ); + const errorEmptyPrompt = useMemo( + () => + hasError ? ( + + + + } + body={ +

+ +

+ } + /> + ) : null, + [hasError] + ); + + const processTree = useMemo( + () => + hasData ? ( +
+ +
+ ) : null, + [ + currentJumpToCursor, + currentJumpToEntityId, + data?.pages, + displayOptions?.timestamp, + displayOptions?.verboseMode, + fetchNextPage, + fetchPreviousPage, + hasData, + hasNextPage, + hasPreviousPage, + investigatedAlertId, + isFetching, + onJumpToOutput, + onProcessSelected, + onShowAlertDetails, + searchQuery, + selectedProcess, + sessionEntityId, + styles.processTree, + trackEvent, + updatedAlertsStatus, + ] + ); + if (renderIsLoading) { return ( @@ -390,103 +501,66 @@ export const SessionView = ({ - - {DETAIL_PANEL} - + {openDetails ? ( + + ) : ( + + {DETAIL_PANEL} + + )} - - {(EuiResizablePanel, EuiResizableButton, { togglePanel }) => { - detailPanelCollapseFn.current = () => { - togglePanel?.(sessionViewId, { direction: 'left' }); - }; - - return ( - <> - - {hasError ? ( - - - - } - body={ -

- -

- } + {openDetails ? ( + <> + {errorEmptyPrompt} + {processTree} + + ) : ( + + {(EuiResizablePanel, EuiResizableButton, { togglePanel }) => { + detailPanelCollapseFn.current = () => { + togglePanel?.(sessionViewId, { direction: 'left' }); + }; + + return ( + <> + + {errorEmptyPrompt} + {processTree} + + + + - ) : null} - - {hasData && ( -
- -
- )} -
- - - - - - - ); - }} -
+
+ + ); + }} +
+ )} { + // console.group('SessionViewDetailPanel'); + // console.log('index', index); + // console.log('alerts', alerts); + // console.log('alertsCount', alertsCount); + // console.log('isFetchingAlerts', isFetchingAlerts); + // console.log('hasNextPageAlerts', hasNextPageAlerts); + // // console.log('fetchNextPageAlerts', fetchNextPageAlerts); + // console.log('investigatedAlertId', investigatedAlertId); + // console.log('selectedProcess', selectedProcess); + // // console.log('onJumpToEvent', onJumpToEvent); + // // console.log('onShowAlertDetails', onShowAlertDetails); + // console.groupEnd(); const [selectedTabId, setSelectedTabId] = useState('process'); const alertsCountStr = useMemo(() => { @@ -142,3 +154,5 @@ export const SessionViewDetailPanel = ({ ); }; +// eslint-disable-next-line import/no-default-export +export { SessionViewDetailPanel as default }; diff --git a/x-pack/plugins/session_view/public/index.ts b/x-pack/plugins/session_view/public/index.ts index 9911332807808..7a0113476e929 100644 --- a/x-pack/plugins/session_view/public/index.ts +++ b/x-pack/plugins/session_view/public/index.ts @@ -13,3 +13,8 @@ export { ENTRY_SESSION_ENTITY_ID_PROPERTY } from '../common'; export function plugin() { return new SessionViewPlugin(); } + +export { DetailPanelProcessTab } from './components/detail_panel_process_tab'; +export { DetailPanelMetadataTab } from './components/detail_panel_metadata_tab'; +export { DetailPanelAlertTab } from './components/detail_panel_alert_tab'; +export { useFetchSessionViewAlerts } from './components/session_view/hooks'; diff --git a/x-pack/plugins/session_view/public/methods/index.tsx b/x-pack/plugins/session_view/public/methods/index.tsx index 43295737c21f1..755999f370e3e 100644 --- a/x-pack/plugins/session_view/public/methods/index.tsx +++ b/x-pack/plugins/session_view/public/methods/index.tsx @@ -10,6 +10,7 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import { METRIC_TYPE } from '@kbn/analytics'; +import { SessionViewDetailPanelDeps } from '../components/session_view_detail_panel'; import type { SessionViewIndex } from '../../common/types/v1'; import { SessionViewDeps, SessionViewTelemetryKey } from '../types'; import { USAGE_COLLECTION_APP_NAME } from '../../common/constants'; @@ -18,6 +19,7 @@ import { USAGE_COLLECTION_APP_NAME } from '../../common/constants'; const queryClient = new QueryClient(); const SessionViewLazy = lazy(() => import('../components/session_view')); +const SessionViewDetailPanelLazy = lazy(() => import('../components/session_view_detail_panel')); export const ELASTIC_DEFEND_DATA_SOURCE = 'endpoint'; export const CLOUD_DEFEND_DATA_SOURCE = 'cloud_defend'; @@ -79,3 +81,16 @@ export const getSessionViewLazy = ( ); }; + +export const getSessionViewDetailPanelLazy = (props: SessionViewDetailPanelDeps) => { + console.log('getSessionViewDetailPanelLazy'); + const index = getIndexPattern(props.index); + + return ( + + }> + + + + ); +}; diff --git a/x-pack/plugins/session_view/public/plugin.ts b/x-pack/plugins/session_view/public/plugin.ts index 0805f0c889b19..fd471056e9a45 100644 --- a/x-pack/plugins/session_view/public/plugin.ts +++ b/x-pack/plugins/session_view/public/plugin.ts @@ -6,6 +6,7 @@ */ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { SessionViewDetailPanelDeps } from './components/session_view_detail_panel'; import { SessionViewPluginStart, SessionViewPluginStartDeps, @@ -13,7 +14,7 @@ import { SessionViewPluginSetupDeps, SessionViewDeps, } from './types'; -import { getSessionViewLazy } from './methods'; +import { getSessionViewLazy, getSessionViewDetailPanelLazy } from './methods'; export class SessionViewPlugin implements Plugin { public setup(core: CoreSetup) { @@ -24,6 +25,8 @@ export class SessionViewPlugin implements Plugin getSessionViewLazy({ ...sessionViewDeps, usageCollection: plugins?.usageCollection }), + getSessionViewDetailPanel: (sessionViewDetailPanelDeps: SessionViewDetailPanelDeps) => + getSessionViewDetailPanelLazy(sessionViewDetailPanelDeps), }; } diff --git a/x-pack/plugins/session_view/public/types.ts b/x-pack/plugins/session_view/public/types.ts index 79161248d7a51..f11137094f44d 100644 --- a/x-pack/plugins/session_view/public/types.ts +++ b/x-pack/plugins/session_view/public/types.ts @@ -9,6 +9,8 @@ import type { UsageCollectionSetup, UsageCollectionStart, } from '@kbn/usage-collection-plugin/public'; +import type { Process } from '../common'; +import { SessionViewDetailPanelDeps } from './components/session_view_detail_panel'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface SessionViewPluginSetup {} @@ -84,6 +86,7 @@ export interface SessionViewDeps { handleOnAlertDetailsClosed: () => void ) => void; canReadPolicyManagement?: boolean; + openDetails?: (selectedProcess: Process | null) => void; } export interface EuiTabProps { @@ -196,4 +199,5 @@ export interface DetailPanelCloud { export interface SessionViewStart { getSessionView: (props: SessionViewDeps) => JSX.Element; + getSessionViewDetailPanel: (props: SessionViewDetailPanelDeps) => JSX.Element; } diff --git a/x-pack/plugins/session_view/server/routes/process_events_route.ts b/x-pack/plugins/session_view/server/routes/process_events_route.ts index b30b3b6ddcc51..308780c7de5d5 100644 --- a/x-pack/plugins/session_view/server/routes/process_events_route.ts +++ b/x-pack/plugins/session_view/server/routes/process_events_route.ts @@ -13,18 +13,12 @@ import type { AlertsClient, RuleRegistryPluginStartContract, } from '@kbn/rule-registry-plugin/server'; -import { EVENT_ACTION } from '@kbn/rule-data-utils'; import { ALERTS_PER_PROCESS_EVENTS_PAGE, PROCESS_EVENTS_ROUTE, PROCESS_EVENTS_PER_PAGE, ENTRY_SESSION_ENTITY_ID_PROPERTY, - TIMESTAMP_PROPERTY, PROCESS_EVENT_FIELDS, - EVENT_ACTION_EXECUTED, - EVENT_ACTION_END, - EVENT_ACTION_EXEC, - EVENT_ACTION_FORK, } from '../../common/constants'; import { ProcessEvent } from '../../common'; import { searchAlerts } from './alerts_route'; @@ -118,24 +112,24 @@ export const fetchEventsAndScopedAlerts = async ( bool: { must: [ { term: { [ENTRY_SESSION_ENTITY_ID_PROPERTY]: sessionEntityId } }, - { - bool: { - should: [ - { term: { [EVENT_ACTION]: EVENT_ACTION_FORK } }, - { term: { [EVENT_ACTION]: EVENT_ACTION_EXEC } }, - { term: { [EVENT_ACTION]: EVENT_ACTION_EXECUTED } }, - { term: { [EVENT_ACTION]: EVENT_ACTION_END } }, - ], - }, - }, - { - range: { - // optimization to prevent data before this session from being hit. - [TIMESTAMP_PROPERTY]: { - gte: sessionStartTime, - }, - }, - }, + // { + // bool: { + // should: [ + // { term: { [EVENT_ACTION]: EVENT_ACTION_FORK } }, + // { term: { [EVENT_ACTION]: EVENT_ACTION_EXEC } }, + // { term: { [EVENT_ACTION]: EVENT_ACTION_EXECUTED } }, + // { term: { [EVENT_ACTION]: EVENT_ACTION_END } }, + // ], + // }, + // }, + // { + // range: { + // // optimization to prevent data before this session from being hit. + // [TIMESTAMP_PROPERTY]: { + // gte: sessionStartTime, + // }, + // }, + // }, ], }, },