-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Security Solution] Decompose Timelines TGrid component and moved to security_solution #140151
Changes from 119 commits
0ec0282
9e8731e
3c92729
cf24c16
5eb7981
c10487a
503d4d2
71fc629
260f5b4
100f09c
b6bc376
077b617
1a446c2
103c4c8
43506dc
d619243
160a35c
910feca
ad6b139
1602ee0
12a5870
85b1db0
44e50e9
6f88d6b
532ad9b
b829b6d
916806e
e3a2854
87c8b1a
15ee420
fdae09c
521f30a
9bdf9f1
2f41ba5
af87402
ffa2cf6
88bc08e
0373af1
d2b06c8
24dc14e
b70b058
fa166e3
7952340
efa5964
15b6179
af31e0e
144b7d5
2e117e2
de06554
8dd06e2
4ba7610
17f1588
0fd8e74
cb509ed
5695725
1390bc5
ff02cd9
1a079b2
01a5328
f26fac0
869ae92
ca9fd2f
c978118
5719060
b3f49b1
1955be3
56296c4
31145ff
9a602a3
5260619
330c575
bc847cd
55c3545
c9d7f8f
bc6f3b9
0db58b4
3aae772
a738412
096c04f
56df471
da6b0be
cd9a224
bf01ef3
517a157
01dadd4
1571c62
a1e281c
c074b58
cef5047
0ba3147
7552174
bb34bdd
2502ca1
766c8fe
ce2c4d5
488b902
d62a59d
2674695
9dc8434
d4ec045
715b3c3
df43a00
cd5177d
b29dcc2
5d54480
c924c7d
6c97408
8fd903c
fb59e52
6b2b5c7
9559973
0394d27
4186d21
212cf1f
13d9e58
6ce4107
45807c4
1859834
0785cea
90c9693
f353a4e
19ffeb7
f94ff58
6471f9b
68e048e
000e7bf
0c76216
c2c1883
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest to stick to the approach proposed in #138600 and organize these common files around subdomains, e.g. it could be Also, for this specific folder |
||
* 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 type { TimelineItem } from '../../search_strategy'; | ||
export interface CustomBulkAction { | ||
key: string; | ||
label: string; | ||
disableOnQuery?: boolean; | ||
disabledLabel?: string; | ||
onClick: (items?: TimelineItem[]) => void; | ||
['data-test-subj']?: string; | ||
} | ||
|
||
export type CustomBulkActionProp = Omit<CustomBulkAction, 'onClick'> & { | ||
onClick: (eventIds: string[]) => void; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* 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 * as runtimeTypes from 'io-ts'; | ||
|
||
export enum Direction { | ||
asc = 'asc', | ||
desc = 'desc', | ||
} | ||
|
||
export type SortDirectionTable = 'none' | 'asc' | 'desc' | Direction; | ||
export interface SortColumnTable { | ||
columnId: string; | ||
columnType: string; | ||
esTypes?: string[]; | ||
sortDirection: SortDirectionTable; | ||
} | ||
|
||
export type { TableById } from '../../../public/common/store/data_table/types'; | ||
|
||
export enum TableId { | ||
usersPageEvents = 'users-page-events', | ||
hostsPageEvents = 'hosts-page-events', | ||
networkPageEvents = 'network-page-events', | ||
hostsPageSessions = 'hosts-page-sessions-v2', // the v2 is to cache bust localstorage settings as default columns were reworked. | ||
alertsOnRuleDetailsPage = 'alerts-rules-details-page', | ||
alertsOnAlertsPage = 'alerts-page', | ||
test = 'table-test', // Reserved for testing purposes | ||
alternateTest = 'alternateTest', | ||
rulePreview = 'rule-preview', | ||
kubernetesPageSessions = 'kubernetes-page-sessions', | ||
} | ||
|
||
const TableIdLiteralRt = runtimeTypes.union([ | ||
runtimeTypes.literal(TableId.usersPageEvents), | ||
runtimeTypes.literal(TableId.hostsPageEvents), | ||
runtimeTypes.literal(TableId.networkPageEvents), | ||
runtimeTypes.literal(TableId.hostsPageSessions), | ||
runtimeTypes.literal(TableId.alertsOnRuleDetailsPage), | ||
runtimeTypes.literal(TableId.alertsOnAlertsPage), | ||
runtimeTypes.literal(TableId.test), | ||
runtimeTypes.literal(TableId.rulePreview), | ||
runtimeTypes.literal(TableId.kubernetesPageSessions), | ||
]); | ||
export type TableIdLiteral = runtimeTypes.TypeOf<typeof TableIdLiteralRt>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* 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 type { FlowTargetSourceDest } from '../../search_strategy'; | ||
import type { TimelineTabs } from '../timeline'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
type EmptyObject = Record<any, never>; | ||
YulNaumenko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
export type ExpandedEventType = | ||
| { | ||
panelView?: 'eventDetail'; | ||
params?: { | ||
eventId: string; | ||
indexName: string; | ||
refetch?: () => void; | ||
}; | ||
} | ||
| EmptyObject; | ||
|
||
export type ExpandedHostType = | ||
| { | ||
panelView?: 'hostDetail'; | ||
params?: { | ||
hostName: string; | ||
}; | ||
} | ||
| EmptyObject; | ||
|
||
export type ExpandedNetworkType = | ||
| { | ||
panelView?: 'networkDetail'; | ||
params?: { | ||
ip: string; | ||
flowTarget: FlowTargetSourceDest; | ||
}; | ||
} | ||
| EmptyObject; | ||
|
||
export type ExpandedUserType = | ||
| { | ||
panelView?: 'userDetail'; | ||
params?: { | ||
userName: string; | ||
}; | ||
} | ||
| EmptyObject; | ||
|
||
export type ExpandedDetailType = | ||
| ExpandedEventType | ||
| ExpandedHostType | ||
| ExpandedNetworkType | ||
| ExpandedUserType; | ||
|
||
export type ExpandedDetailTimeline = { | ||
[tab in TimelineTabs]?: ExpandedDetailType; | ||
}; | ||
|
||
export type ExpandedDetail = Partial<Record<string, ExpandedDetailType>>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/* | ||
* 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 type { | ||
EuiDataGridCellValueElementProps, | ||
EuiDataGridColumn, | ||
EuiDataGridColumnCellActionProps, | ||
EuiDataGridControlColumn, | ||
} from '@elastic/eui'; | ||
import type { IFieldSubType } from '@kbn/es-query'; | ||
import type { FieldBrowserOptions } from '@kbn/triggers-actions-ui-plugin/public'; | ||
import type { ComponentType, JSXElementConstructor, ReactNode } from 'react'; | ||
import type { OnRowSelected, SetEventsDeleted, SetEventsLoading } from '..'; | ||
import type { Ecs } from '../../ecs'; | ||
import type { BrowserFields, TimelineNonEcsData } from '../../search_strategy'; | ||
import type { SortColumnTable } from '../data_table'; | ||
|
||
export type ColumnHeaderType = 'not-filtered' | 'text-filter'; | ||
|
||
/** Uniquely identifies a column */ | ||
export type ColumnId = string; | ||
|
||
/** | ||
* A `DataTableCellAction` function accepts `data`, where each row of data is | ||
* represented as a `TimelineNonEcsData[]`. For example, `data[0]` would | ||
* contain a `TimelineNonEcsData[]` with the first row of data. | ||
* | ||
* A `DataTableCellAction` returns a function that has access to all the | ||
* `EuiDataGridColumnCellActionProps`, _plus_ access to `data`, | ||
* which enables code like the following example to be written: | ||
* | ||
* Example: | ||
* ``` | ||
* ({ data }: { data: TimelineNonEcsData[][] }) => ({ rowIndex, columnId, Component }) => { | ||
* const value = getMappedNonEcsValue({ | ||
* data: data[rowIndex], // access a specific row's values | ||
* fieldName: columnId, | ||
* }); | ||
* | ||
* return ( | ||
* <Component onClick={() => alert(`row ${rowIndex} col ${columnId} has value ${value}`)} iconType="heart"> | ||
* {'Love it'} | ||
* </Component> | ||
* ); | ||
* }; | ||
* ``` | ||
*/ | ||
export type DataTableCellAction = ({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this here and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, due to the usage by hover actions of |
||
browserFields, | ||
data, | ||
ecsData, | ||
header, | ||
pageSize, | ||
scopeId, | ||
closeCellPopover, | ||
}: { | ||
browserFields: BrowserFields; | ||
/** each row of data is represented as one TimelineNonEcsData[] */ | ||
data: TimelineNonEcsData[][]; | ||
ecsData: Ecs[]; | ||
header?: ColumnHeaderOptions; | ||
pageSize: number; | ||
scopeId: string; | ||
closeCellPopover?: () => void; | ||
}) => (props: EuiDataGridColumnCellActionProps) => ReactNode; | ||
|
||
/** The specification of a column header */ | ||
export type ColumnHeaderOptions = Pick< | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for this type as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By the reason I've mentioned above - we need this type for hover actions and Observability still use it by some reason. |
||
EuiDataGridColumn, | ||
| 'actions' | ||
| 'defaultSortDirection' | ||
| 'display' | ||
| 'displayAsText' | ||
| 'id' | ||
| 'initialWidth' | ||
| 'isSortable' | ||
| 'schema' | ||
> & { | ||
aggregatable?: boolean; | ||
dataTableCellActions?: DataTableCellAction[]; | ||
category?: string; | ||
columnHeaderType: ColumnHeaderType; | ||
description?: string | null; | ||
esTypes?: string[]; | ||
example?: string | number | null; | ||
format?: string; | ||
linkField?: string; | ||
placeholder?: string; | ||
subType?: IFieldSubType; | ||
type?: string; | ||
}; | ||
export interface HeaderActionProps { | ||
width: number; | ||
browserFields: BrowserFields; | ||
columnHeaders: ColumnHeaderOptions[]; | ||
fieldBrowserOptions?: FieldBrowserOptions; | ||
isEventViewer?: boolean; | ||
isSelectAllChecked: boolean; | ||
onSelectAll: ({ isSelected }: { isSelected: boolean }) => void; | ||
showEventsSelect: boolean; | ||
showSelectAllCheckbox: boolean; | ||
sort: SortColumnTable[]; | ||
tabType: string; | ||
timelineId: string; | ||
} | ||
|
||
export type HeaderCellRender = ComponentType | ComponentType<HeaderActionProps>; | ||
|
||
type GenericActionRowCellRenderProps = Pick< | ||
EuiDataGridCellValueElementProps, | ||
'rowIndex' | 'columnId' | ||
>; | ||
|
||
export type RowCellRender = | ||
| JSXElementConstructor<GenericActionRowCellRenderProps> | ||
| ((props: GenericActionRowCellRenderProps) => JSX.Element) | ||
| JSXElementConstructor<ActionProps> | ||
| ((props: ActionProps) => JSX.Element); | ||
|
||
export interface ActionProps { | ||
action?: RowCellRender; | ||
ariaRowindex: number; | ||
checked: boolean; | ||
columnId: string; | ||
columnValues: string; | ||
data: TimelineNonEcsData[]; | ||
disabled?: boolean; | ||
ecsData: Ecs; | ||
eventId: string; | ||
eventIdToNoteIds?: Readonly<Record<string, string[]>>; | ||
index: number; | ||
isEventPinned?: boolean; | ||
isEventViewer?: boolean; | ||
loadingEventIds: Readonly<string[]>; | ||
onEventDetailsPanelOpened: () => void; | ||
onRowSelected: OnRowSelected; | ||
onRuleChange?: () => void; | ||
refetch?: () => void; | ||
rowIndex: number; | ||
setEventsDeleted: SetEventsDeleted; | ||
setEventsLoading: SetEventsLoading; | ||
showCheckboxes: boolean; | ||
showNotes?: boolean; | ||
tabType?: string; | ||
timelineId: string; | ||
toggleShowNotes?: () => void; | ||
width?: number; | ||
} | ||
|
||
interface AdditionalControlColumnProps { | ||
ariaRowindex: number; | ||
actionsColumnWidth: number; | ||
columnValues: string; | ||
checked: boolean; | ||
onRowSelected: OnRowSelected; | ||
eventId: string; | ||
id: string; | ||
columnId: string; | ||
loadingEventIds: Readonly<string[]>; | ||
onEventDetailsPanelOpened: () => void; | ||
showCheckboxes: boolean; | ||
// Override these type definitions to support either a generic custom component or the one used in security_solution today. | ||
headerCellRender: HeaderCellRender; | ||
rowCellRender: RowCellRender; | ||
} | ||
|
||
export type ControlColumnProps = Omit< | ||
EuiDataGridControlColumn, | ||
keyof AdditionalControlColumnProps | ||
> & | ||
Partial<AdditionalControlColumnProps>; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,4 +5,18 @@ | |
* 2.0. | ||
*/ | ||
|
||
import type { Status } from '../detection_engine/schemas/common'; | ||
|
||
export * from './timeline'; | ||
export * from './data_table'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for splitting up the types like this. Much cleaner! |
||
export * from './detail_panel'; | ||
export * from './header_actions'; | ||
export * from './session_view'; | ||
export * from './bulk_actions'; | ||
|
||
export const FILTER_OPEN: Status = 'open'; | ||
export const FILTER_CLOSED: Status = 'closed'; | ||
export const FILTER_ACKNOWLEDGED: Status = 'acknowledged'; | ||
|
||
export type SetEventsLoading = (params: { eventIds: string[]; isLoading: boolean }) => void; | ||
export type SetEventsDeleted = (params: { eventIds: string[]; isDeleted: boolean }) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This more for any observability folks reading this, but I think we should move away from using this format and using the raw
SearchHit
or a more generalized agreed upon Kibana wide formatting. All this is, is a formatted fields response https://github.com/elastic/kibana/blob/main/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.ts#L52-L56 and I think it adds an unnecessary layer of complexity at times since there's really nothingTimeline
specific about itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, but I don't know which type Observability team prefer here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@XavierM as you're the author of the
TimelineNonEcsData
interface, perhaps you have a suggestion as to what a better type here would be for Observability purposes?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the new alert table, we are deprecating this type but we had to keep it for security solution since a lot of functionality is working around this data/type. We need to figure out, how we are going to fully deprecated on your side. However, o11y and stack should not use it.