Skip to content

Commit 0f40804

Browse files
[SECURITY SOLUTION] Bundles _source -> Fields + able to sort on multiple fields in Timeline (#83761)
* replace _source with fields * wip * unit test * regroup sorting and number together * fix bugs from review * mistake * Update x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/index.tsx Co-authored-by: Patryk Kopyciński <contact@patrykkopycinski.com> * fix snapshot * review + fix topN and filter from detail view * fix tests * fix test Co-authored-by: Patryk Kopyciński <contact@patrykkopycinski.com>
1 parent c9b5ec7 commit 0f40804

69 files changed

Lines changed: 1474 additions & 608 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

x-pack/plugins/security_solution/common/search_strategy/security_solution/matrix_histogram/events/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface EventsActionGroupData {
2828
export interface EventHit extends SearchHit {
2929
sort: string[];
3030
_source: EventSource;
31+
fields: Record<string, unknown[]>;
3132
aggregations: {
3233
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3334
[agg: string]: any;

x-pack/plugins/security_solution/common/search_strategy/timeline/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest {
3131
export interface TimelineRequestOptionsPaginated<Field = string>
3232
extends TimelineRequestBasicOptions {
3333
pagination: Pick<PaginationInputPaginated, 'activePage' | 'querySize'>;
34-
sort: SortField<Field>;
34+
sort: Array<SortField<Field>>;
3535
}
3636

3737
export type TimelineStrategyResponseType<

x-pack/plugins/security_solution/common/types/timeline/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,15 @@ const SavedFavoriteRuntimeType = runtimeTypes.partial({
143143
/*
144144
* Sort Types
145145
*/
146-
const SavedSortRuntimeType = runtimeTypes.partial({
146+
147+
const SavedSortObject = runtimeTypes.partial({
147148
columnId: unionWithNullType(runtimeTypes.string),
148149
sortDirection: unionWithNullType(runtimeTypes.string),
149150
});
151+
const SavedSortRuntimeType = runtimeTypes.union([
152+
runtimeTypes.array(SavedSortObject),
153+
SavedSortObject,
154+
]);
150155

151156
/*
152157
* Timeline Statuses

x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ describe('Events Viewer', () => {
157157

158158
it('re-orders columns via drag and drop', () => {
159159
const originalColumnOrder =
160-
'@timestampmessagehost.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';
160+
'@timestamp1messagehost.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';
161161
const expectedOrderAfterDragAndDrop =
162-
'message@timestamphost.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';
162+
'message@timestamp1host.nameevent.moduleevent.datasetevent.actionuser.namesource.ipdestination.ip';
163163

164164
cy.get(HEADERS_GROUP).invoke('text').should('equal', originalColumnOrder);
165165
dragAndDropColumn({ column: 0, newPosition: 0 });
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"savedObjectId":"0162c130-78be-11ea-9718-118a926974a4","version":"WzcsMV0=","columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"message"},{"columnHeaderType":"not-filtered","id":"event.category"},{"columnHeaderType":"not-filtered","id":"event.action"},{"columnHeaderType":"not-filtered","id":"host.name"},{"columnHeaderType":"not-filtered","id":"source.ip"},{"columnHeaderType":"not-filtered","id":"destination.ip"},{"columnHeaderType":"not-filtered","id":"user.name"}],"created":1586256805054,"createdBy":"elastic","dataProviders":[],"dateRange":{"end":1586256837669,"start":1546343624710},"description":"description","eventType":"all","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"expression":"host.name:*","kind":"kuery"},"serializedQuery":"{\"bool\":{\"should\":[{\"exists\":{\"field\":\"host.name\"}}],\"minimum_should_match\":1}}"}},"savedQueryId":null,"sort":{"columnId":"@timestamp","sortDirection":"desc"},"title":"SIEM test","updated":1586256839298,"updatedBy":"elastic","timelineType":"default","eventNotes":[],"globalNotes":[],"pinnedEventIds":[]}
1+
{"savedObjectId":"0162c130-78be-11ea-9718-118a926974a4","version":"WzcsMV0=","columns":[{"columnHeaderType":"not-filtered","id":"@timestamp"},{"columnHeaderType":"not-filtered","id":"message"},{"columnHeaderType":"not-filtered","id":"event.category"},{"columnHeaderType":"not-filtered","id":"event.action"},{"columnHeaderType":"not-filtered","id":"host.name"},{"columnHeaderType":"not-filtered","id":"source.ip"},{"columnHeaderType":"not-filtered","id":"destination.ip"},{"columnHeaderType":"not-filtered","id":"user.name"}],"created":1586256805054,"createdBy":"elastic","dataProviders":[],"dateRange":{"end":1586256837669,"start":1546343624710},"description":"description","eventType":"all","filters":[],"kqlMode":"filter","kqlQuery":{"filterQuery":{"kuery":{"expression":"host.name:*","kind":"kuery"},"serializedQuery":"{\"bool\":{\"should\":[{\"exists\":{\"field\":\"host.name\"}}],\"minimum_should_match\":1}}"}},"savedQueryId":null,"sort":[{"columnId":"@timestamp","sortDirection":"desc"}],"title":"SIEM test","updated":1586256839298,"updatedBy":"elastic","timelineType":"default","eventNotes":[],"globalNotes":[],"pinnedEventIds":[]}

x-pack/plugins/security_solution/public/common/components/drag_and_drop/draggable_wrapper_hover_content.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { allowTopN } from './helpers';
1919
import * as i18n from './translations';
2020
import { useManageTimeline } from '../../../timelines/components/manage_timeline';
2121
import { TimelineId } from '../../../../common/types/timeline';
22-
import { SELECTOR_TIMELINE_BODY_CLASS_NAME } from '../../../timelines/components/timeline/styles';
22+
import { SELECTOR_TIMELINE_GLOBAL_CONTAINER } from '../../../timelines/components/timeline/styles';
2323
import { SourcererScopeName } from '../../store/sourcerer/model';
2424
import { useSourcererScope } from '../../containers/sourcerer';
2525

@@ -230,7 +230,7 @@ export const useGetTimelineId = function (
230230
if (
231231
myElem != null &&
232232
myElem.classList != null &&
233-
myElem.classList.contains(SELECTOR_TIMELINE_BODY_CLASS_NAME) &&
233+
myElem.classList.contains(SELECTOR_TIMELINE_GLOBAL_CONTAINER) &&
234234
myElem.hasAttribute('data-timeline-id')
235235
) {
236236
setTimelineId(myElem.getAttribute('data-timeline-id'));

x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,12 @@ const eventsViewerDefaultProps = {
7979
language: 'kql',
8080
},
8181
start: from,
82-
sort: {
83-
columnId: 'foo',
84-
sortDirection: 'none' as SortDirection,
85-
},
82+
sort: [
83+
{
84+
columnId: 'foo',
85+
sortDirection: 'none' as SortDirection,
86+
},
87+
],
8688
scopeId: SourcererScopeName.timeline,
8789
utilityBar,
8890
};

x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ interface Props {
115115
query: Query;
116116
onRuleChange?: () => void;
117117
start: string;
118-
sort: Sort;
118+
sort: Sort[];
119119
utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode;
120120
// If truthy, the graph viewer (Resolver) is showing
121121
graphEventId: string | undefined;
@@ -202,11 +202,12 @@ const EventsViewerComponent: React.FC<Props> = ({
202202
]);
203203

204204
const sortField = useMemo(
205-
() => ({
206-
field: sort.columnId,
207-
direction: sort.sortDirection as Direction,
208-
}),
209-
[sort.columnId, sort.sortDirection]
205+
() =>
206+
sort.map(({ columnId, sortDirection }) => ({
207+
field: columnId,
208+
direction: sortDirection as Direction,
209+
})),
210+
[sort]
210211
);
211212

212213
const [
@@ -341,7 +342,7 @@ export const EventsViewer = React.memo(
341342
prevProps.kqlMode === nextProps.kqlMode &&
342343
deepEqual(prevProps.query, nextProps.query) &&
343344
prevProps.start === nextProps.start &&
344-
prevProps.sort === nextProps.sort &&
345+
deepEqual(prevProps.sort, nextProps.sort) &&
345346
prevProps.utilityBar === nextProps.utilityBar &&
346347
prevProps.graphEventId === nextProps.graphEventId
347348
);

x-pack/plugins/security_solution/public/common/mock/global_state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ export const mockGlobalState: State = {
239239
pinnedEventIds: {},
240240
pinnedEventsSaveObject: {},
241241
itemsPerPageOptions: [5, 10, 20],
242-
sort: { columnId: '@timestamp', sortDirection: Direction.desc },
242+
sort: [{ columnId: '@timestamp', sortDirection: Direction.desc }],
243243
isSaving: false,
244244
version: null,
245245
status: TimelineStatus.active,

x-pack/plugins/security_solution/public/common/mock/timeline_results.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2142,10 +2142,12 @@ export const mockTimelineModel: TimelineModel = {
21422142
selectedEventIds: {},
21432143
show: false,
21442144
showCheckboxes: false,
2145-
sort: {
2146-
columnId: '@timestamp',
2147-
sortDirection: Direction.desc,
2148-
},
2145+
sort: [
2146+
{
2147+
columnId: '@timestamp',
2148+
sortDirection: Direction.desc,
2149+
},
2150+
],
21492151
status: TimelineStatus.active,
21502152
title: 'Test rule',
21512153
timelineType: TimelineType.default,
@@ -2177,7 +2179,7 @@ export const mockTimelineResult: TimelineResult = {
21772179
templateTimelineId: null,
21782180
templateTimelineVersion: null,
21792181
savedQueryId: null,
2180-
sort: { columnId: '@timestamp', sortDirection: 'desc' },
2182+
sort: [{ columnId: '@timestamp', sortDirection: 'desc' }],
21812183
version: '1',
21822184
};
21832185

@@ -2247,7 +2249,7 @@ export const defaultTimelineProps: CreateTimelineProps = {
22472249
selectedEventIds: {},
22482250
show: false,
22492251
showCheckboxes: false,
2250-
sort: { columnId: '@timestamp', sortDirection: Direction.desc },
2252+
sort: [{ columnId: '@timestamp', sortDirection: Direction.desc }],
22512253
status: TimelineStatus.draft,
22522254
title: '',
22532255
timelineType: TimelineType.default,

0 commit comments

Comments
 (0)