From b3774e83dd525ff4c198e8aac3b3359c6ffe8b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ece=20=C3=96zalp?= Date: Tue, 3 Aug 2021 17:47:54 -0400 Subject: [PATCH] [CTI] updates Alert Summary UI (#107081) --- .../event_details/alert_summary_view.tsx | 17 +++-- .../components/event_details/columns.tsx | 4 +- .../cti_details/threat_details_view.tsx | 1 - .../cti_details/threat_summary_view.test.tsx | 22 ++++-- .../cti_details/threat_summary_view.tsx | 75 +++++++++++++------ .../event_details/event_details.tsx | 2 + .../components/event_details/helpers.tsx | 16 ++-- .../event_details/table/action_cell.tsx | 6 +- .../event_details/table/field_name_cell.tsx | 2 +- .../event_details/table/field_value_cell.tsx | 6 +- .../table/use_action_cell_data_provider.ts | 2 +- .../common/components/event_details/types.ts | 7 ++ .../common/components/hover_actions/index.tsx | 1 + 13 files changed, 108 insertions(+), 53 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx index 501ef78d550f9..500f14aaa5317 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx @@ -38,7 +38,6 @@ import { getEmptyValue } from '../empty_value'; import { ActionCell } from './table/action_cell'; import { FieldValueCell } from './table/field_value_cell'; import { TimelineEventsDetailsItem } from '../../../../common'; -import { EventFieldsData } from './types'; export const Indent = styled.div` padding: 0 8px; @@ -95,15 +94,11 @@ const getDescription = ({ return {getEmptyValue()}; } - const eventFieldsData = { - ...data, - ...(fieldFromBrowserField ? fieldFromBrowserField : {}), - } as EventFieldsData; return ( <> get(browserFields, keys), + (keys: string[], browserFields: BrowserFields): BrowserField => get(browserFields, keys), (newArgs, lastArgs) => newArgs[0].join() === lastArgs[0].join() ); export const getColumns = ({ diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx index 4b91b432bd553..67c490a33693b 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx @@ -191,7 +191,6 @@ const ThreatDetailsViewComponent: React.FC<{
{i18n.INVESTIGATION_TOOLTIP_TITLE}
- {/* TODO: Date form */} { const mount = useMountAppended(); const eventId = '5d1d53da502f56aacc14c3cb5c669363d102b31f99822e5d369d4804ed370a31'; const timelineId = 'detections-page'; - - beforeEach(() => { - jest.clearAllMocks(); - }); + const data = mockAlertDetailsData as TimelineEventsDetailsItem[]; + const browserFields = mockBrowserFields; it('renders a row for each enrichment', () => { const enrichments = [ - buildEventEnrichmentMock(), + buildEventEnrichmentMock({ 'matched.id': ['test.id'], 'matched.field': ['test.field'] }), buildEventEnrichmentMock({ 'matched.id': ['other.id'], 'matched.field': ['other.field'] }), ]; const wrapper = mount( - + ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx index 363ce6a227c27..3ab59be650732 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx @@ -6,15 +6,19 @@ */ import styled from 'styled-components'; -import React from 'react'; +import { get } from 'lodash/fp'; +import React, { Fragment } from 'react'; import { EuiBasicTableColumn, EuiText, EuiTitle } from '@elastic/eui'; import * as i18n from './translations'; import { Indent, StyledEuiInMemoryTable } from '../summary_view'; -import { FormattedFieldValue } from '../../../../timelines/components/timeline/body/renderers/formatted_field'; import { CtiEnrichment } from '../../../../../common/search_strategy/security_solution/cti'; import { getEnrichmentIdentifiers } from './helpers'; import { EnrichmentIcon } from './enrichment_icon'; +import { FieldsData } from '../types'; +import { ActionCell } from '../table/action_cell'; +import { BrowserField, BrowserFields, TimelineEventsDetailsItem } from '../../../../../common'; +import { FieldValueCell } from '../table/field_value_cell'; export interface ThreatSummaryItem { title: { @@ -22,12 +26,13 @@ export interface ThreatSummaryItem { type: string | undefined; }; description: { - timelineId: string; + browserField: BrowserField; + data: FieldsData | undefined; eventId: string; - fieldName: string | undefined; index: number; - value: string | undefined; provider: string | undefined; + timelineId: string; + value: string | undefined; }; } @@ -48,24 +53,25 @@ const EnrichmentTitle: React.FC = ({ title, type }) ); const EnrichmentDescription: React.FC = ({ - timelineId, + browserField, + data, eventId, - fieldName, index, - value, provider, + timelineId, + value, }) => { - const key = `alert-details-value-formatted-field-value-${timelineId}-${eventId}-${fieldName}-${value}-${index}-${provider}`; + if (!data || !value) return null; + const key = `alert-details-value-formatted-field-value-${timelineId}-${eventId}-${data.field}-${value}-${index}-${provider}`; return ( - <> + - {provider && ( @@ -82,17 +88,39 @@ const EnrichmentDescription: React.FC = ({ )} - + {value && ( + + )} + ); }; const buildThreatSummaryItems = ( + browserFields: BrowserFields, + data: TimelineEventsDetailsItem[], enrichments: CtiEnrichment[], timelineId: string, eventId: string ) => { return enrichments.map((enrichment, index) => { const { field, type, value, provider } = getEnrichmentIdentifiers(enrichment); + const eventData = data.find((item) => item.field === field); + const category = eventData?.category ?? ''; + const browserField = get([category, 'fields', field ?? ''], browserFields); + + const fieldsData = { + field, + format: browserField?.format ?? '', + type: browserField?.type ?? '', + isObjectArray: eventData?.isObjectArray, + }; return { title: { @@ -101,11 +129,12 @@ const buildThreatSummaryItems = ( }, description: { eventId, - fieldName: field, index, provider, timelineId, value, + data: fieldsData, + browserField, }, }; }); @@ -116,7 +145,7 @@ const columns: Array> = [ field: 'title', truncateText: false, render: EnrichmentTitle, - width: '160px', + width: '220px', name: '', }, { @@ -131,13 +160,15 @@ const ThreatSummaryViewComponent: React.FC<{ enrichments: CtiEnrichment[]; timelineId: string; eventId: string; -}> = ({ enrichments, timelineId, eventId }) => ( + data: TimelineEventsDetailsItem[]; + browserFields: BrowserFields; +}> = ({ enrichments, timelineId, eventId, data, browserFields }) => ( ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx index 0d31db1f7124c..1d639eb9497fc 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx @@ -145,6 +145,8 @@ const EventDetailsComponent: React.FC = ({ /> {enrichmentCount > 0 && ( >>; + fieldFromBrowserField?: BrowserField; linkValue: string | undefined; timelineId: string; values: string[] | null | undefined; @@ -196,9 +198,13 @@ export const onEventDetailsTabKeyPressed = ({ } }; +const StyledH5 = styled.h5` + line-height: 1.7rem; +`; + const getTitle = (title: string) => ( -
{title}
+ {title}
); getTitle.displayName = 'getTitle'; @@ -213,7 +219,7 @@ export const getSummaryColumns = ( field: 'title', truncateText: false, render: getTitle, - width: '33%', + width: '220px', name: '', }, { diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/action_cell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/table/action_cell.tsx index 67b1874eea0a0..f35765c1cac04 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/table/action_cell.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/action_cell.tsx @@ -8,17 +8,17 @@ import React, { useCallback, useState, useRef } from 'react'; import { HoverActions } from '../../hover_actions'; import { useActionCellDataProvider } from './use_action_cell_data_provider'; -import { EventFieldsData } from '../types'; +import { EventFieldsData, FieldsData } from '../types'; import { useGetTimelineId } from '../../drag_and_drop/use_get_timeline_id_from_dom'; import { ColumnHeaderOptions } from '../../../../../common/types/timeline'; import { BrowserField } from '../../../containers/source'; interface Props { contextId: string; - data: EventFieldsData; + data: FieldsData | EventFieldsData; disabled?: boolean; eventId: string; - fieldFromBrowserField?: Readonly>>; + fieldFromBrowserField?: BrowserField; getLinkValue?: (field: string) => string | null; linkValue?: string | null | undefined; onFilterAdded?: () => void; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx index e62d7f90b9f1d..edf4bdf0e8e3c 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_name_cell.tsx @@ -19,7 +19,7 @@ import { getFieldTypeName } from './get_field_type_name'; export interface FieldNameCellProps { data: EventFieldsData; field: string; - fieldFromBrowserField: Readonly>>; + fieldFromBrowserField: BrowserField; fieldMapping?: IndexPatternField; scripted?: boolean; } diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_value_cell.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_value_cell.tsx index 68d0b479cb1ca..bf19384b0d0aa 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/table/field_value_cell.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/field_value_cell.tsx @@ -11,13 +11,13 @@ import { BrowserField } from '../../../containers/source'; import { OverflowField } from '../../tables/helpers'; import { FormattedFieldValue } from '../../../../timelines/components/timeline/body/renderers/formatted_field'; import { MESSAGE_FIELD_NAME } from '../../../../timelines/components/timeline/body/renderers/constants'; -import { EventFieldsData } from '../types'; +import { EventFieldsData, FieldsData } from '../types'; export interface FieldValueCellProps { contextId: string; - data: EventFieldsData; + data: EventFieldsData | FieldsData; eventId: string; - fieldFromBrowserField?: Readonly>>; + fieldFromBrowserField?: BrowserField; getLinkValue?: (field: string) => string | null; linkValue?: string | null | undefined; values: string[] | null | undefined; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts b/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts index abf467aa42bca..76ca5dfe53f4e 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/table/use_action_cell_data_provider.ts @@ -35,7 +35,7 @@ export interface UseActionCellDataProvider { eventId?: string; field: string; fieldFormat?: string; - fieldFromBrowserField?: Readonly>>; + fieldFromBrowserField?: BrowserField; fieldType?: string; isObjectArray?: boolean; linkValue?: string | null; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/types.ts b/x-pack/plugins/security_solution/public/common/components/event_details/types.ts index a8c5026d9868f..0f077147f0705 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/types.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/types.ts @@ -9,3 +9,10 @@ import { BrowserField } from '../../containers/source'; import { TimelineEventsDetailsItem } from '../../../../common/search_strategy'; export type EventFieldsData = BrowserField & TimelineEventsDetailsItem; + +export interface FieldsData { + field: string; + format: string; + type: string; + isObjectArray: boolean; +} diff --git a/x-pack/plugins/security_solution/public/common/components/hover_actions/index.tsx b/x-pack/plugins/security_solution/public/common/components/hover_actions/index.tsx index a1ba33f30cc55..907e4005d6d2b 100644 --- a/x-pack/plugins/security_solution/public/common/components/hover_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/hover_actions/index.tsx @@ -40,6 +40,7 @@ export const AdditionalContent = styled.div` AdditionalContent.displayName = 'AdditionalContent'; const StyledHoverActionsContainer = styled.div<{ $showTopN: boolean; $showOwnFocus: boolean }>` + min-width: 138px; padding: ${(props) => `0 ${props.theme.eui.paddingSizes.s}`}; display: flex;