> = getSummaryColumns(
+ ThreatDetailsDescription
+);
+
+const ThreatDetailsViewComponent: React.FC<{
+ data: TimelineEventsDetailsItem[];
+}> = ({ data }) => {
+ const summaryRowsArray = useMemo(() => getSummaryRowsArray({ data }), [data]);
+ return (
+ <>
+ {summaryRowsArray.map((summaryRows, index, arr) => {
+ const key = summaryRows.find((threat) => threat.title === 'matched.id')?.description
+ .value[0];
+ return (
+
+
+ {index < arr.length - 1 && }
+
+ );
+ })}
+ >
+ );
+};
+
+export const ThreatDetailsView = React.memo(ThreatDetailsViewComponent);
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.test.tsx
new file mode 100644
index 0000000000000..756fc7d32b371
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.test.tsx
@@ -0,0 +1,44 @@
+/*
+ * 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 from 'react';
+
+import { ThreatSummaryView } from './threat_summary_view';
+import { mockAlertDetailsData } from './__mocks__';
+import { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
+
+import { TestProviders } from '../../mock';
+import { useMountAppended } from '../../utils/use_mount_appended';
+
+jest.mock('../../../detections/containers/detection_engine/rules/use_rule_async', () => {
+ return {
+ useRuleAsync: jest.fn(),
+ };
+});
+
+const props = {
+ data: mockAlertDetailsData as TimelineEventsDetailsItem[],
+ eventId: '5d1d53da502f56aacc14c3cb5c669363d102b31f99822e5d369d4804ed370a31',
+ timelineId: 'detections-page',
+};
+
+describe('ThreatSummaryView', () => {
+ const mount = useMountAppended();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test('render correct items', () => {
+ const wrapper = mount(
+
+
+
+ );
+ expect(wrapper.find('[data-test-subj="threat-summary-view"]').exists()).toEqual(true);
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.tsx
new file mode 100644
index 0000000000000..96ae2071c449b
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/threat_summary_view.tsx
@@ -0,0 +1,89 @@
+/*
+ * 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 { EuiBasicTableColumn } from '@elastic/eui';
+import React, { useMemo } from 'react';
+
+import { TimelineEventsDetailsItem } from '../../../../common/search_strategy';
+import { FormattedFieldValue } from '../../../timelines/components/timeline/body/renderers/formatted_field';
+import { BrowserFields } from '../../../../common/search_strategy/index_fields';
+import { SummaryView } from './summary_view';
+import { getSummaryColumns, SummaryRow, ThreatSummaryRow } from './helpers';
+import { INDICATOR_DESTINATION_PATH } from '../../../../common/constants';
+
+const getDescription = ({
+ contextId,
+ eventId,
+ fieldName,
+ values,
+}: ThreatSummaryRow['description']): JSX.Element => (
+ <>
+ {values.map((value: string) => (
+
+ ))}
+ >
+);
+
+const getSummaryRows = ({
+ data,
+ timelineId: contextId,
+ eventId,
+}: {
+ data: TimelineEventsDetailsItem[];
+ browserFields?: BrowserFields;
+ timelineId: string;
+ eventId: string;
+}) => {
+ if (!data) return [];
+ return data.reduce((acc, { field, originalValue }) => {
+ if (field.startsWith(`${INDICATOR_DESTINATION_PATH}.`) && originalValue) {
+ return [
+ ...acc,
+ {
+ title: field.replace(`${INDICATOR_DESTINATION_PATH}.`, ''),
+ description: {
+ values: Array.isArray(originalValue) ? originalValue : [originalValue],
+ contextId,
+ eventId,
+ fieldName: field,
+ },
+ },
+ ];
+ }
+ return acc;
+ }, []);
+};
+
+const summaryColumns: Array> = getSummaryColumns(getDescription);
+
+const ThreatSummaryViewComponent: React.FC<{
+ data: TimelineEventsDetailsItem[];
+ eventId: string;
+ timelineId: string;
+}> = ({ data, eventId, timelineId }) => {
+ const summaryRows = useMemo(() => getSummaryRows({ data, eventId, timelineId }), [
+ data,
+ eventId,
+ timelineId,
+ ]);
+
+ return (
+
+ );
+};
+
+export const ThreatSummaryView = React.memo(ThreatSummaryViewComponent);
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 3a599b174251a..73a2e0d57307c 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
@@ -11,6 +11,14 @@ export const SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.summa
defaultMessage: 'Summary',
});
+export const THREAT_SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.threatSummary', {
+ defaultMessage: 'Threat Summary',
+});
+
+export const THREAT_DETAILS = i18n.translate('xpack.securitySolution.alertDetails.threatDetails', {
+ defaultMessage: 'Threat Details',
+});
+
export const INVESTIGATION_GUIDE = i18n.translate(
'xpack.securitySolution.alertDetails.summary.investigationGuide',
{
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 87392bce3ee63..50970304953ca 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
@@ -262,7 +262,7 @@ Array [
-ms-flex: 1;
flex: 1;
overflow: hidden;
- padding: 4px 16px 64px;
+ padding: 4px 16px 50px;
}
.c0 {
@@ -537,7 +537,7 @@ Array [
-ms-flex: 1;
flex: 1;
overflow: hidden;
- padding: 4px 16px 64px;
+ padding: 4px 16px 50px;
}
.c0 {
@@ -806,7 +806,7 @@ Array [
-ms-flex: 1;
flex: 1;
overflow: hidden;
- padding: 4px 16px 64px;
+ padding: 4px 16px 50px;
}
.c0 {
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 435a210b9d260..86175c0e06ad2 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
@@ -26,7 +26,8 @@ import { BrowserFields } from '../../../../common/containers/source';
import {
EventDetails,
EventsViewType,
- View,
+ EventView,
+ ThreatView,
} from '../../../../common/components/event_details/event_details';
import { TimelineEventsDetailsItem } from '../../../../../common/search_strategy/timeline';
import { LineClamp } from '../../../../common/components/line_clamp';
@@ -87,7 +88,8 @@ ExpandableEventTitle.displayName = 'ExpandableEventTitle';
export const ExpandableEvent = React.memo(
({ browserFields, event, timelineId, timelineTabType, isAlert, loading, detailsData }) => {
- const [view, setView] = useState(EventsViewType.summaryView);
+ const [eventView, setEventView] = useState(EventsViewType.summaryView);
+ const [threatView, setThreatView] = useState(EventsViewType.threatSummaryView);
const message = useMemo(() => {
if (detailsData) {
@@ -131,10 +133,12 @@ export const ExpandableEvent = React.memo(
data={detailsData!}
id={event.eventId!}
isAlert={isAlert}
- onViewSelected={setView}
- timelineTabType={timelineTabType}
+ onThreatViewSelected={setThreatView}
+ onEventViewSelected={setEventView}
+ threatView={threatView}
timelineId={timelineId}
- view={view}
+ timelineTabType={timelineTabType}
+ eventView={eventView}
/>
diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx
index 6f4778f36466b..9a4684193b997 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/event_details/index.tsx
@@ -25,7 +25,7 @@ const StyledEuiFlyoutBody = styled(EuiFlyoutBody)`
.euiFlyoutBody__overflowContent {
flex: 1;
overflow: hidden;
- padding: ${({ theme }) => `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 64px`};
+ padding: ${({ theme }) => `${theme.eui.paddingSizes.xs} ${theme.eui.paddingSizes.m} 50px`};
}
}
`;
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx
index 3032f556251f3..e227c87b99870 100644
--- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx
+++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/formatted_field.tsx
@@ -44,7 +44,7 @@ const FormattedFieldValueComponent: React.FC<{
isObjectArray?: boolean;
fieldFormat?: string;
fieldName: string;
- fieldType: string;
+ fieldType?: string;
truncate?: boolean;
value: string | number | undefined | null;
linkValue?: string | null | undefined;
diff --git a/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts b/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts
index 4dab0ebc43149..0b418c0da410c 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts
@@ -7,7 +7,7 @@
import { mapValues, isObject, isArray } from 'lodash/fp';
-import { toArray } from './to_array';
+import { toArray } from '../../../common/utils/to_array';
export const mapObjectValuesToStringArray = (object: object): object =>
mapValues((o) => {
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts
index 3f4eb5721164b..bed4a040f92b0 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts
@@ -14,8 +14,7 @@ import {
HostsEdges,
HostValue,
} from '../../../../../../common/search_strategy/security_solution/hosts';
-
-import { toObjectArrayOfStrings } from '../../../../helpers/to_array';
+import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array';
export const HOSTS_FIELDS: readonly string[] = [
'_id',
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts
index aeaefe690cbde..807b78cb9cdd2 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts
@@ -8,7 +8,7 @@
import { get, getOr, isEmpty } from 'lodash/fp';
import { set } from '@elastic/safer-lodash-set/fp';
import { mergeFieldsWithHit } from '../../../../../utils/build_query';
-import { toObjectArrayOfStrings } from '../../../../helpers/to_array';
+import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array';
import {
AuthenticationsEdges,
AuthenticationHit,
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
index d36af61957690..00ed5c0c0dc01 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
@@ -8,6 +8,7 @@
import { set } from '@elastic/safer-lodash-set/fp';
import { get, has, head } from 'lodash/fp';
import { hostFieldsMap } from '../../../../../../common/ecs/ecs_fields';
+import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array';
import { Direction } from '../../../../../../common/search_strategy/common';
import {
AggregationRequest,
@@ -16,7 +17,6 @@ import {
HostItem,
HostValue,
} from '../../../../../../common/search_strategy/security_solution/hosts';
-import { toObjectArrayOfStrings } from '../../../../helpers/to_array';
export const HOST_FIELDS = [
'_id',
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts
index fe202b48540d7..1c1e2111f3771 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/uncommon_processes/helpers.ts
@@ -14,7 +14,7 @@ import {
HostsUncommonProcessesEdges,
HostsUncommonProcessHit,
} from '../../../../../../common/search_strategy/security_solution/hosts/uncommon_processes';
-import { toObjectArrayOfStrings } from '../../../../helpers/to_array';
+import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array';
import { HostHits } from '../../../../../../common/search_strategy';
export const uncommonProcessesFields = [
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts
index 8fc7ae0304a35..cc1bfdff8e096 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/helpers.ts
@@ -13,7 +13,7 @@ import {
NetworkDetailsHostHit,
NetworkHit,
} from '../../../../../../common/search_strategy/security_solution/network';
-import { toObjectArrayOfStrings } from '../../../../helpers/to_array';
+import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array';
export const getNetworkDetailsAgg = (type: string, networkHit: NetworkHit | {}) => {
const firstSeen = getOr(null, `firstSeen.value_as_string`, networkHit);
diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts
index 61af6a7664faa..405ddba137dae 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.test.ts
@@ -8,7 +8,7 @@
import { EventHit } from '../../../../../../common/search_strategy';
import { TIMELINE_EVENTS_FIELDS } from './constants';
import { formatTimelineData } from './helpers';
-import { eventHit } from '../mocks';
+import { eventHit } from '../../../../../../common/utils/mock_event_details';
describe('#formatTimelineData', () => {
it('happy path', async () => {
diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts
index e5bb8cb7e14b7..2c18fb2840865 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/all/helpers.ts
@@ -11,8 +11,11 @@ import {
TimelineEdges,
TimelineNonEcsData,
} from '../../../../../../common/search_strategy';
-import { toStringArray } from '../../../../helpers/to_array';
-import { getDataSafety, getDataFromFieldsHits } from '../details/helpers';
+import { toStringArray } from '../../../../../../common/utils/to_array';
+import {
+ getDataFromFieldsHits,
+ getDataSafety,
+} from '../../../../../../common/utils/field_formatters';
const getTimestamp = (hit: EventHit): string => {
if (hit.fields && hit.fields['@timestamp']) {
diff --git a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts
index 0107ba44baec7..a4d6eebfb71b8 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/timeline/factory/events/details/index.ts
@@ -19,7 +19,11 @@ import {
import { inspectStringifyObject } from '../../../../../utils/build_query';
import { SecuritySolutionTimelineFactory } from '../../types';
import { buildTimelineDetailsQuery } from './query.events_details.dsl';
-import { getDataFromFieldsHits, getDataFromSourceHits, getDataSafety } from './helpers';
+import {
+ getDataFromFieldsHits,
+ getDataFromSourceHits,
+ getDataSafety,
+} from '../../../../../../common/utils/field_formatters';
export const timelineEventsDetails: SecuritySolutionTimelineFactory = {
buildDsl: (options: TimelineEventsDetailsRequestOptions) => {