From 85f726c3d88062b7a1a3d724af227943bb5ee670 Mon Sep 17 00:00:00 2001 From: Angela Chuang <6295984+angorayc@users.noreply.github.com> Date: Tue, 20 Jul 2021 12:52:05 +0100 Subject: [PATCH] [Security Solution] Alert flyout overview (#105602) * init flyout overview * styling * remove reason block * rm unused i18n key * show data by event category * rename styled component * update snapshot * update overview tab on alert flyout * styling * fix up * update snapshot and remove unused i18n --- .../event_details/alert_summary_view.tsx | 72 +++++++++++++------ .../cti_details/threat_summary_view.tsx | 2 +- .../event_details/event_details.test.tsx | 6 +- .../event_details/event_details.tsx | 3 +- .../components/event_details/helpers.tsx | 2 +- .../components/event_details/summary_view.tsx | 47 +++++------- .../components/event_details/translations.ts | 17 +++-- .../components/alerts_table/translations.ts | 14 ++++ .../__snapshots__/index.test.tsx.snap | 21 ++---- .../event_details/expandable_event.tsx | 46 +++--------- .../side_panel/event_details/index.tsx | 63 ++++++++++------ .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 13 files changed, 156 insertions(+), 141 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 329b8e32f057d..841aa6840cc0b 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 @@ -5,13 +5,7 @@ * 2.0. */ -import { - EuiBasicTableColumn, - EuiDescriptionList, - EuiDescriptionListDescription, - EuiDescriptionListTitle, - EuiSpacer, -} from '@elastic/eui'; +import { EuiBasicTableColumn, EuiSpacer, EuiHorizontalRule, EuiTitle, EuiText } from '@elastic/eui'; import { get, getOr, find } from 'lodash/fp'; import React, { useMemo } from 'react'; import styled from 'styled-components'; @@ -27,6 +21,8 @@ import { ALERTS_HEADERS_THRESHOLD_CARDINALITY, ALERTS_HEADERS_THRESHOLD_COUNT, ALERTS_HEADERS_THRESHOLD_TERMS, + SIGNAL_STATUS, + TIMESTAMP, } from '../../../detections/components/alerts_table/translations'; import { IP_FIELD_TYPE, @@ -40,14 +36,14 @@ import { MarkdownRenderer } from '../markdown_editor'; import { LineClamp } from '../line_clamp'; import { endpointAlertCheck } from '../../utils/endpoint_alert_check'; -const StyledEuiDescriptionList = styled(EuiDescriptionList)` - padding: 24px 4px 4px; +export const Indent = styled.div` + padding: 0 8px; word-break: break-word; `; const fields = [ - { id: 'signal.status' }, - { id: '@timestamp' }, + { id: 'signal.status', label: SIGNAL_STATUS }, + { id: '@timestamp', label: TIMESTAMP }, { id: SIGNAL_RULE_NAME_FIELD_NAME, linkField: 'signal.rule.id', @@ -65,6 +61,20 @@ const fields = [ { id: 'signal.threshold_result.cardinality', label: ALERTS_HEADERS_THRESHOLD_CARDINALITY }, ]; +const processFields = [ + ...fields, + { id: 'process.name' }, + { id: 'process.parent.name' }, + { id: 'process.args' }, +]; + +const networkFields = [ + ...fields, + { id: 'destination.address' }, + { id: 'destination.port' }, + { id: 'process.name' }, +]; + const getDescription = ({ contextId, eventId, @@ -94,8 +104,22 @@ const getSummaryRows = ({ timelineId: string; eventId: string; }) => { + const categoryField = find({ category: 'event', field: 'event.category' }, data) as + | TimelineEventsDetailsItem + | undefined; + const eventCategory = Array.isArray(categoryField?.originalValue) + ? categoryField?.originalValue[0] + : categoryField?.originalValue; + + const tableFields = + eventCategory === 'network' + ? networkFields + : eventCategory === 'process' + ? processFields + : fields; + return data != null - ? fields.reduce((acc, item) => { + ? tableFields.reduce((acc, item) => { const field = data.find((d) => d.field === item.id); if (!field) { return acc; @@ -213,21 +237,27 @@ const AlertSummaryViewComponent: React.FC<{ return ( <> - + {maybeRule?.note && ( - - {i18n.INVESTIGATION_GUIDE} - - - {maybeRule.note} - - - + <> + + +
{i18n.INVESTIGATION_GUIDE}
+
+ + + + + {maybeRule.note} + + + + )} ); 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 274e292f5d1c2..16b4e7ff7c44d 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 @@ -38,7 +38,7 @@ const RightMargin = styled.span` const EnrichmentTitle: React.FC = ({ title, type }) => ( <> - +
{title}
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx index 539993b59c70d..f323a8c8b4a08 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.test.tsx @@ -82,7 +82,7 @@ describe('EventDetails', () => { }); describe('alerts tabs', () => { - ['Summary', 'Threat Intel', 'Table', 'JSON View'].forEach((tab) => { + ['Overview', 'Threat Intel', 'Table', 'JSON View'].forEach((tab) => { test(`it renders the ${tab} tab`, () => { const expectedCopy = tab === 'Threat Intel' ? `${tab} (1)` : tab; expect( @@ -94,14 +94,14 @@ describe('EventDetails', () => { }); }); - test('the Summary tab is selected by default', () => { + test('the Overview tab is selected by default', () => { expect( alertsWrapper .find('[data-test-subj="eventDetails"]') .find('.euiTab-isSelected') .first() .text() - ).toEqual('Summary'); + ).toEqual('Overview'); }); }); 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 668c6ffb723aa..39a8af135a990 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 @@ -128,7 +128,7 @@ const EventDetailsComponent: React.FC = ({ isAlert ? { id: EventsViewType.summaryView, - name: i18n.SUMMARY, + name: i18n.OVERVIEW, content: ( <> = ({ eventId: id, browserFields, timelineId, + title: i18n.DUCOMENT_SUMMARY, }} /> {enrichmentCount > 0 && ( diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx index 6002f66da4309..2b300789c4d14 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/helpers.tsx @@ -197,7 +197,7 @@ export const onEventDetailsTabKeyPressed = ({ }; const getTitle = (title: string) => ( - +
{title}
); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx index 961860ed6d8b9..ddfa632d0199a 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx @@ -5,12 +5,16 @@ * 2.0. */ -import { EuiInMemoryTable, EuiBasicTableColumn, EuiTitle, EuiHorizontalRule } from '@elastic/eui'; +import { EuiInMemoryTable, EuiBasicTableColumn, EuiTitle } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; import { SummaryRow } from './helpers'; +export const Indent = styled.div` + padding: 0 4px; +`; + // eslint-disable-next-line @typescript-eslint/no-explicit-any export const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)` .euiTableHeaderCell, @@ -22,24 +26,6 @@ export const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)` } `; -const StyledEuiTitle = styled(EuiTitle)` - color: ${({ theme }) => theme.eui.euiColorDarkShade}; - text-transform: lowercase; - padding-top: ${({ theme }) => theme.eui.paddingSizes.s}; - h2 { - min-width: 120px; - } - hr { - max-width: 75%; - } -`; - -const FlexDiv = styled.div` - display: flex; - align-items: center; - justify-content: flex-start; -`; - export const SummaryViewComponent: React.FC<{ title?: string; summaryColumns: Array>; @@ -49,19 +35,18 @@ export const SummaryViewComponent: React.FC<{ return ( <> {title && ( - - -

{title}

- -
-
+ +
{title}
+
)} - + + + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts index c632f5d6332e0..56d5009c34d72 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts @@ -7,21 +7,28 @@ import { i18n } from '@kbn/i18n'; -export const SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.summary', { - defaultMessage: 'Summary', -}); - export const THREAT_INTEL = i18n.translate('xpack.securitySolution.alertDetails.threatIntel', { defaultMessage: 'Threat Intel', }); export const INVESTIGATION_GUIDE = i18n.translate( - 'xpack.securitySolution.alertDetails.summary.investigationGuide', + 'xpack.securitySolution.alertDetails.overview.investigationGuide', { defaultMessage: 'Investigation guide', } ); +export const OVERVIEW = i18n.translate('xpack.securitySolution.alertDetails.overview', { + defaultMessage: 'Overview', +}); + +export const DUCOMENT_SUMMARY = i18n.translate( + 'xpack.securitySolution.alertDetails.overview.documentSummary', + { + defaultMessage: 'Document Summary', + } +); + export const TABLE = i18n.translate('xpack.securitySolution.eventDetails.table', { defaultMessage: 'Table', }); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts b/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts index c43c4547a17ec..ec86b00e3ac81 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/translations.ts @@ -245,9 +245,23 @@ export const STATUS = i18n.translate( } ); +export const SIGNAL_STATUS = i18n.translate( + 'xpack.securitySolution.eventsViewer.alerts.overviewTable.signalStatusTitle', + { + defaultMessage: 'Status', + } +); + export const TRIGGERED = i18n.translate( 'xpack.securitySolution.eventsViewer.alerts.defaultHeaders.triggeredTitle', { defaultMessage: 'Triggered', } ); + +export const TIMESTAMP = i18n.translate( + 'xpack.securitySolution.eventsViewer.alerts.overviewTable.timestampTitle', + { + defaultMessage: 'Timestamp', + } +); diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap index edf1a50787a57..8118555cd64d8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/__snapshots__/index.test.tsx.snap @@ -56,6 +56,7 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should handleOnEventClosed={[Function]} isAlert={false} loading={true} + ruleName="" >
- -
+ />
- -
+ />
@@ -522,6 +516,7 @@ Array [
- -
+ /> diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx index 47f6fe6606d3d..31cc61d4996a8 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/expandable_event.tsx @@ -5,27 +5,22 @@ * 2.0. */ -import { find } from 'lodash/fp'; +import { isEmpty } from 'lodash/fp'; import { EuiButtonIcon, EuiTextColor, EuiLoadingContent, EuiTitle, - EuiSpacer, - EuiDescriptionList, - EuiDescriptionListTitle, - EuiDescriptionListDescription, EuiFlexGroup, EuiFlexItem, } from '@elastic/eui'; -import React, { useMemo } from 'react'; +import React from 'react'; import styled from 'styled-components'; import { TimelineTabs } from '../../../../../common/types/timeline'; import { BrowserFields } from '../../../../common/containers/source'; import { EventDetails } from '../../../../common/components/event_details/event_details'; import { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline'; -import { LineClamp } from '../../../../common/components/line_clamp'; import * as i18n from './translations'; export type HandleOnEventClosed = () => void; @@ -43,6 +38,7 @@ interface Props { interface ExpandableEventTitleProps { isAlert: boolean; loading: boolean; + ruleName?: string; handleOnEventClosed?: HandleOnEventClosed; } @@ -63,12 +59,14 @@ const StyledEuiFlexItem = styled(EuiFlexItem)` `; export const ExpandableEventTitle = React.memo( - ({ isAlert, loading, handleOnEventClosed }) => ( + ({ isAlert, loading, handleOnEventClosed, ruleName }) => ( - - {!loading ?

{isAlert ? i18n.ALERT_DETAILS : i18n.EVENT_DETAILS}

: <>} -
+ {!loading && ( + +

{isAlert && !isEmpty(ruleName) ? ruleName : i18n.EVENT_DETAILS}

+
+ )}
{handleOnEventClosed && ( @@ -83,21 +81,6 @@ ExpandableEventTitle.displayName = 'ExpandableEventTitle'; export const ExpandableEvent = React.memo( ({ browserFields, event, timelineId, timelineTabType, isAlert, loading, detailsData }) => { - const message = useMemo(() => { - if (detailsData) { - const messageField = find({ category: 'base', field: 'message' }, detailsData) as - | TimelineEventsDetailsItem - | undefined; - - if (messageField?.originalValue) { - return Array.isArray(messageField?.originalValue) - ? messageField?.originalValue.join() - : messageField?.originalValue; - } - } - return null; - }, [detailsData]); - if (!event.eventId) { return {i18n.EVENT_DETAILS_PLACEHOLDER}; } @@ -108,17 +91,6 @@ export const ExpandableEvent = React.memo( return ( - {message && ( - - - {i18n.MESSAGE} - - {message} - - - - - )} { + const currentField = find({ category, field }, data)?.values; + return currentField && currentField.length > 0 ? currentField[0] : ''; +}; + interface EventDetailsPanelProps { browserFields: BrowserFields; docValueFields: DocValueFields[]; @@ -106,31 +121,34 @@ const EventDetailsPanelComponent: React.FC = ({ return endpointAlertCheck({ data: detailsData || [] }); }, [detailsData]); - const agentId = useMemo(() => { - const findAgentId = find({ category: 'agent', field: 'agent.id' }, detailsData)?.values; - return findAgentId ? findAgentId[0] : ''; - }, [detailsData]); + const ruleName = useMemo( + () => getFieldValue({ category: 'signal', field: 'signal.rule.name' }, detailsData), + [detailsData] + ); - const hostOsFamily = useMemo(() => { - const findOsName = find({ category: 'host', field: 'host.os.name' }, detailsData)?.values; - return findOsName ? findOsName[0] : ''; - }, [detailsData]); + const agentId = useMemo( + () => getFieldValue({ category: 'agent', field: 'agent.id' }, detailsData), + [detailsData] + ); - const agentVersion = useMemo(() => { - const findAgentVersion = find({ category: 'agent', field: 'agent.version' }, detailsData) - ?.values; - return findAgentVersion ? findAgentVersion[0] : ''; - }, [detailsData]); + const hostOsFamily = useMemo( + () => getFieldValue({ category: 'host', field: 'host.os.name' }, detailsData), + [detailsData] + ); - const alertId = useMemo(() => { - const findAlertId = find({ category: '_id', field: '_id' }, detailsData)?.values; - return findAlertId ? findAlertId[0] : ''; - }, [detailsData]); + const agentVersion = useMemo( + () => getFieldValue({ category: 'agent', field: 'agent.version' }, detailsData), + [detailsData] + ); - const hostName = useMemo(() => { - const findHostName = find({ category: 'host', field: 'host.name' }, detailsData)?.values; - return findHostName ? findHostName[0] : ''; - }, [detailsData]); + const alertId = useMemo(() => getFieldValue({ category: '_id', field: '_id' }, detailsData), [ + detailsData, + ]); + + const hostName = useMemo( + () => getFieldValue({ category: 'host', field: 'host.name' }, detailsData), + [detailsData] + ); const isolationSupported = isIsolationSupported({ osName: hostOsFamily, @@ -177,7 +195,7 @@ const EventDetailsPanelComponent: React.FC = ({ {isHostIsolationPanelOpen ? ( backToAlertDetailsLink ) : ( - + )} {isIsolateActionSuccessBannerVisible && ( @@ -225,6 +243,7 @@ const EventDetailsPanelComponent: React.FC = ({ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 9756c38e65f6e..67d1d6cc353ac 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -18540,8 +18540,6 @@ "xpack.securitySolution.administration.os.windows": "Windows", "xpack.securitySolution.alertDetails.checkDocs": "マニュアルをご確認ください。", "xpack.securitySolution.alertDetails.ifCtiNotEnabled": "脅威インテリジェンスソースを有効にしていない場合で、この機能について関心がある場合は、", - "xpack.securitySolution.alertDetails.summary": "まとめ", - "xpack.securitySolution.alertDetails.summary.investigationGuide": "調査ガイド", "xpack.securitySolution.alertDetails.summary.readLess": "表示を減らす", "xpack.securitySolution.alertDetails.summary.readMore": "続きを読む", "xpack.securitySolution.alertDetails.threatIntel": "Threat Intel", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index f1f985406fbd0..da266dbbb41d6 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -18804,8 +18804,6 @@ "xpack.securitySolution.administration.os.windows": "Windows", "xpack.securitySolution.alertDetails.checkDocs": "请查看我们的文档。", "xpack.securitySolution.alertDetails.ifCtiNotEnabled": "如果尚未启用任何威胁情报来源,并希望更多了解此功能,", - "xpack.securitySolution.alertDetails.summary": "摘要", - "xpack.securitySolution.alertDetails.summary.investigationGuide": "调查指南", "xpack.securitySolution.alertDetails.summary.readLess": "阅读更少内容", "xpack.securitySolution.alertDetails.summary.readMore": "阅读更多内容", "xpack.securitySolution.alertDetails.threatIntel": "威胁情报",