From bba02262342a3e9d438c79ad93b97b73cfde7647 Mon Sep 17 00:00:00 2001 From: christineweng Date: Tue, 20 Feb 2024 17:49:07 -0600 Subject: [PATCH] more comments --- .../flyout/document_details/right/context.tsx | 2 +- ....tsx => use_flyout_is_expandable.test.tsx} | 58 +++++++++++++++---- ...verview.ts => use_flyout_is_expandable.ts} | 26 +++++++-- .../flyout/document_details/right/index.tsx | 18 ++---- .../right/utils/event_utils.test.tsx | 20 ++++++- 5 files changed, 95 insertions(+), 29 deletions(-) rename x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/{use_show_event_overview.test.tsx => use_flyout_is_expandable.test.tsx} (59%) rename x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/{use_show_event_overview.ts => use_flyout_is_expandable.ts} (59%) diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx index 0fb3ded93a01b..7311a030b2175 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/context.tsx @@ -8,8 +8,8 @@ import type { BrowserFields, TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import React, { createContext, memo, useContext, useMemo } from 'react'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; - import { TableId } from '@kbn/securitysolution-data-table'; + import { useEventDetails } from '../shared/hooks/use_event_details'; import { FlyoutError } from '../../shared/components/flyout_error'; import { FlyoutLoading } from '../../shared/components/flyout_loading'; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.test.tsx similarity index 59% rename from x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.test.tsx rename to x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.test.tsx index d566ad3f88989..a67bb675a373a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.test.tsx @@ -5,16 +5,50 @@ * 2.0. */ -import { useShowEventOverview } from './use_show_event_overview'; +import { useFlyoutIsExpandable } from './use_flyout_is_expandable'; import { renderHook } from '@testing-library/react-hooks'; import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; const getFieldsData = jest.fn(); +jest.mock('../../../../common/hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: jest.fn().mockReturnValue(true), +})); +const useIsExperimentalFeatureEnabledMock = useIsExperimentalFeatureEnabled as jest.Mock; -describe('showEventOverview', () => { - describe('event renderer is not available', () => { +describe('useFlyoutIsExpandable', () => { + it('always return ture when event.kind is signal (alert document)', () => { + const dataAsNestedObject = {} as unknown as Ecs; + getFieldsData.mockImplementation((field: string) => { + if (field === 'event.kind') { + return 'signal'; + } + }); + const hookResult = renderHook(() => + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }).valueOf() + ); + expect(hookResult.result.current).toBe(true); + }); + + it('always return false when event.kind is not signal and feature flag is off', () => { const dataAsNestedObject = {} as unknown as Ecs; + useIsExperimentalFeatureEnabledMock.mockReturnValue(false); + getFieldsData.mockImplementation((field: string) => { + if (field === 'event.kind') { + return 'signal'; + } + }); + const hookResult = renderHook(() => + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }).valueOf() + ); + expect(hookResult.result.current).toBe(true); + }); + describe('event renderer is not available', () => { + beforeEach(() => { + useIsExperimentalFeatureEnabledMock.mockReturnValue(true); + }); + const dataAsNestedObject = {} as unknown as Ecs; describe('event.kind is not event', () => { it('should return true if event.kind is in ecs allowed values', () => { getFieldsData.mockImplementation((field: string) => { @@ -23,7 +57,7 @@ describe('showEventOverview', () => { } }); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }).valueOf() + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }).valueOf() ); expect(hookResult.result.current).toBe(true); }); @@ -35,7 +69,7 @@ describe('showEventOverview', () => { } }); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(false); }); @@ -43,7 +77,7 @@ describe('showEventOverview', () => { it('should return false if event.kind is notavailable', () => { getFieldsData.mockImplementation(() => {}); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(false); }); @@ -60,7 +94,7 @@ describe('showEventOverview', () => { } }); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(true); }); @@ -75,7 +109,7 @@ describe('showEventOverview', () => { } }); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(false); }); @@ -86,7 +120,7 @@ describe('showEventOverview', () => { } }); const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(false); }); @@ -95,9 +129,13 @@ describe('showEventOverview', () => { describe('event renderer is available', () => { const dataAsNestedObject = { event: { module: ['suricata'] } } as unknown as Ecs; + beforeEach(() => { + useIsExperimentalFeatureEnabledMock.mockReturnValue(true); + }); + it('should return true', () => { const hookResult = renderHook(() => - useShowEventOverview({ getFieldsData, dataAsNestedObject }) + useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }) ); expect(hookResult.result.current).toBe(true); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.ts similarity index 59% rename from x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.ts rename to x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.ts index 6e1eb4811179c..8e465b31ce8e0 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_show_event_overview.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/hooks/use_flyout_is_expandable.ts @@ -12,6 +12,8 @@ import type { GetFieldsData } from '../../../../common/hooks/use_get_fields_data import { getRowRenderer } from '../../../../timelines/components/timeline/body/renderers/get_row_renderer'; import { defaultRowRenderers } from '../../../../timelines/components/timeline/body/renderers'; import { isEcsAllowedValue } from '../utils/event_utils'; +import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { EventKind } from '../../shared/constants/event_kinds'; export interface UseShowEventOverviewParams { /** @@ -25,9 +27,11 @@ export interface UseShowEventOverviewParams { } /** - * Hook to return true if overview should be visible + * Hook used on the right panel to decide if the flyout has an expanded section. + * This also helps deciding if the overview section should be displayed. + * The hook looks at the `event.kind` and `event.category` fields of the document. */ -export const useShowEventOverview = ({ +export const useFlyoutIsExpandable = ({ getFieldsData, dataAsNestedObject, }: UseShowEventOverviewParams): boolean => { @@ -41,10 +45,24 @@ export const useShowEventOverview = ({ isEcsAllowedValue('event.category', category) ); + const expandableEventFlyoutEnabled = useIsExperimentalFeatureEnabled( + 'expandableEventFlyoutEnabled' + ); + return useMemo(() => { - if (eventKind === 'event') { + // alert document: always show overview + if (eventKind === EventKind.signal) { + return true; + } + // do not show overview for non-alert if feature flag is disabled + if (!expandableEventFlyoutEnabled) { + return false; + } + // event document: show overview when event category is ecs compliant or event renderer is available + if (eventKind === EventKind.event) { return eventCategoryInECS || renderer != null; } + // non-event document: show overview when event kind is ecs compliant or event renderer is available return eventKindInECS || renderer != null; - }, [eventKind, eventCategoryInECS, eventKindInECS, renderer]); + }, [expandableEventFlyoutEnabled, eventKind, eventCategoryInECS, eventKindInECS, renderer]); }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx index d37932651ec52..52bb1aa45daf2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/index.tsx @@ -16,10 +16,7 @@ import { PanelContent } from './content'; import type { RightPanelTabType } from './tabs'; import * as tabs from './tabs'; import { PanelFooter } from './footer'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; -import { useShowEventOverview } from './hooks/use_show_event_overview'; -import { getField } from '../shared/utils'; -import { EventKind } from '../shared/constants/event_kinds'; +import { useFlyoutIsExpandable } from './hooks/use_flyout_is_expandable'; export type RightPanelPaths = 'overview' | 'table' | 'json'; export const DocumentDetailsRightPanelKey: RightPanelProps['key'] = 'document-details-right'; @@ -41,18 +38,13 @@ export const RightPanel: FC> = memo(({ path }) => { const { openRightPanel, closeFlyout } = useExpandableFlyoutApi(); const { eventId, indexName, scopeId, isPreview, dataAsNestedObject, getFieldsData } = useRightPanelContext(); - const isEventKindSignal = getField(getFieldsData('event.kind')) === EventKind.signal; - const expandableEventFlyoutEnabled = useIsExperimentalFeatureEnabled( - 'expandableEventFlyoutEnabled' - ); - const showEventOverview = - useShowEventOverview({ getFieldsData, dataAsNestedObject }) && expandableEventFlyoutEnabled; + const flyoutIsExpandable = useFlyoutIsExpandable({ getFieldsData, dataAsNestedObject }); const tabsDisplayed = useMemo(() => { - return isEventKindSignal || showEventOverview + return flyoutIsExpandable ? [tabs.overviewTab, tabs.tableTab, tabs.jsonTab] : [tabs.tableTab, tabs.jsonTab]; - }, [isEventKindSignal, showEventOverview]); + }, [flyoutIsExpandable]); const selectedTabId = useMemo(() => { const defaultTab = tabsDisplayed[0].id; @@ -89,7 +81,7 @@ export const RightPanel: FC> = memo(({ path }) => { return ( <> - + { it('should return if the value is an allowed value given by field name', () => { @@ -14,3 +14,21 @@ describe('test isEcsAllowedValue', () => { expect(isEcsAllowedValue('not ecs field', 'file')).toBe(false); }); }); + +describe('test getEcsAllowedValueDescription', () => { + it('should return correct description based on field', () => { + expect(getEcsAllowedValueDescription('event.kind', 'metric')).toBe( + 'This value is used to indicate that this event describes a numeric measurement taken at given point in time.\nExamples include CPU utilization, memory usage, or device temperature.\nMetric events are often collected on a predictable frequency, such as once every few seconds, or once a minute, but can also be used to describe ad-hoc numeric metric queries.' + ); + expect(getEcsAllowedValueDescription('event.category', 'malware')).toBe( + 'Malware detection events and alerts. Use this category to visualize and analyze malware detections from EDR/EPP systems such as Elastic Endpoint Security, Symantec Endpoint Protection, Crowdstrike, and network IDS/IPS systems such as Suricata, or other sources of malware-related events such as Palo Alto Networks threat logs and Wildfire logs.' + ); + + expect(getEcsAllowedValueDescription('event.kind', 'not ecs')).toBe( + 'This field is not an ecs field, description is not available.' + ); + expect(getEcsAllowedValueDescription('event.category', 'not ecs')).toBe( + 'This field is not an ecs field, description is not available.' + ); + }); +});