[SIEM] Add Timestamp to Events Table (#36743) (#36812)

## Summary

This PR updates the `Events` table displayed on the `Host` and `Host Details` page as follows:
* Adds `Timestamp` as first column
* Removes `Event Category` column
* Increases `Message` column width, truncates long values, and moved column to last position

Relevant issues:
https://github.com/elastic/ingest-dev/issues/443

Updated Events Table:
![image](https://user-images.githubusercontent.com/2946766/58067684-71971080-7b4b-11e9-8751-e57b71cc43e6.png)


Previous Events Table:
![image](https://user-images.githubusercontent.com/2946766/58067629-372d7380-7b4b-11e9-854d-357766d1cb91.png)

### Checklist
- [ ] ~This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~
- [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)
- [ ] ~[Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~
- [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
- [ ] ~This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~

### For maintainers

- [ ] ~This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
- [ ] ~This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~
This commit is contained in:
Garrett Spong 2019-05-22 15:44:14 -06:00 committed by GitHub
parent 90435dd95a
commit 7e7cde0ac2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 77 additions and 39 deletions

View file

@ -104,6 +104,7 @@ export interface Columns<T> {
truncateText?: boolean;
hideForMobile?: boolean;
render?: (item: T) => void;
width?: string;
}
export class LoadMoreTable<T, U, V, W, X, Y, Z, AA, AB> extends React.PureComponent<

View file

@ -4,8 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiToolTip } from '@elastic/eui';
import { getOr } from 'lodash/fp';
import React from 'react';
import moment from 'moment';
import { connect } from 'react-redux';
import { pure } from 'recompose';
import { ActionCreator } from 'typescript-fsa';
@ -13,12 +15,15 @@ import { ActionCreator } from 'typescript-fsa';
import { hostsActions } from '../../../../store/actions';
import { Ecs, EcsEdges } from '../../../../graphql/types';
import { hostsModel, hostsSelectors, State } from '../../../../store';
import { getOrEmptyTag } from '../../../empty_value';
import { getEmptyTagValue, getOrEmptyTag } from '../../../empty_value';
import { HostDetailsLink, IPDetailsLink } from '../../../links';
import { Columns, ItemsPerRow, LoadMoreTable } from '../../../load_more_table';
import * as i18n from './translations';
import { getRowItemDraggable, getRowItemDraggables } from '../../../tables/helpers';
import { PreferenceFormattedDate } from '../../../formatted_date';
import { LocalizedDateTooltip } from '../../../localized_date_tooltip';
import { MoreRowItems } from '../../index';
interface OwnProps {
data: Ecs[];
@ -120,10 +125,22 @@ const getEventsColumns = (
Columns<EcsEdges>
] => [
{
name: i18n.HOST_NAME,
sortable: true,
name: i18n.TIMESTAMP,
sortable: false,
truncateText: false,
render: ({ node }) =>
node.timestamp != null ? (
<LocalizedDateTooltip date={moment(new Date(node.timestamp)).toDate()}>
<PreferenceFormattedDate value={new Date(node.timestamp)} />
</LocalizedDateTooltip>
) : (
getEmptyTagValue()
),
},
{
name: i18n.HOST_NAME,
sortable: false,
truncateText: false,
hideForMobile: false,
render: ({ node }) =>
getRowItemDraggables({
rowItems: getOr(null, 'host.name', node),
@ -134,9 +151,8 @@ const getEventsColumns = (
},
{
name: i18n.EVENT_MODULE_DATASET,
sortable: true,
sortable: false,
truncateText: true,
hideForMobile: true,
render: ({ node }) => (
<>
{getRowItemDraggables({
@ -153,23 +169,10 @@ const getEventsColumns = (
</>
),
},
{
name: i18n.EVENT_CATEGORY,
sortable: true,
truncateText: true,
hideForMobile: true,
render: ({ node }) =>
getRowItemDraggables({
rowItems: getOr(null, 'event.category', node),
attrName: 'event.category',
idPrefix: `host-${pageType}-events-table-${node._id}`,
}),
},
{
name: i18n.EVENT_ACTION,
sortable: true,
sortable: false,
truncateText: true,
hideForMobile: true,
render: ({ node }) =>
getRowItemDraggables({
rowItems: getOr(null, 'event.action', node),
@ -179,7 +182,7 @@ const getEventsColumns = (
},
{
name: i18n.USER,
sortable: true,
sortable: false,
truncateText: true,
render: ({ node }) =>
getRowItemDraggables({
@ -188,19 +191,9 @@ const getEventsColumns = (
idPrefix: `host-${pageType}-events-table-${node._id}`,
}),
},
{
name: i18n.MESSAGE,
sortable: false,
truncateText: true,
render: ({ node }) =>
getRowItemDraggables({
rowItems: getOr(null, 'message', node),
attrName: 'message',
idPrefix: `host-${pageType}-events-table-${node._id}`,
}),
},
{
name: i18n.SOURCE,
sortable: false,
truncateText: true,
render: ({ node }) => (
<>
@ -216,7 +209,7 @@ const getEventsColumns = (
},
{
name: i18n.DESTINATION,
sortable: true,
sortable: false,
truncateText: true,
render: ({ node }) => (
<>
@ -230,4 +223,32 @@ const getEventsColumns = (
</>
),
},
{
name: i18n.MESSAGE,
sortable: false,
truncateText: true,
width: '25%',
render: ({ node }) => {
const message = getOr(null, 'message[0]', node);
const overflowLength = 50;
return message != null
? getRowItemDraggable({
rowItem: message,
attrName: 'message',
idPrefix: `host-${pageType}-events-table-${node._id}`,
dragDisplayValue: message.substring(0, overflowLength),
render: () => (
<>
{message.substring(0, overflowLength)}
{message.length > overflowLength && (
<EuiToolTip content={message}>
<MoreRowItems type="boxesHorizontal" />
</EuiToolTip>
)}
</>
),
})
: getEmptyTagValue();
},
},
];

View file

@ -16,6 +16,10 @@ export const UNIT = (totalCount: number) =>
defaultMessage: `{totalCount, plural, =1 {Event} other {Events}}`,
});
export const TIMESTAMP = i18n.translate('xpack.siem.eventsTable.timestampTitle', {
defaultMessage: 'Timestamp',
});
export const HOST_NAME = i18n.translate('xpack.siem.eventsTable.hostsNameTitle', {
defaultMessage: 'Host Name',
});
@ -24,10 +28,6 @@ export const EVENT_ACTION = i18n.translate('xpack.siem.eventsTable.eventTypeActi
defaultMessage: 'Event Action',
});
export const EVENT_CATEGORY = i18n.translate('xpack.siem.eventsTable.eventCategoryTitle', {
defaultMessage: 'Event Category',
});
export const SOURCE = i18n.translate('xpack.siem.eventsTable.sourceTitle', {
defaultMessage: 'Source',
});

View file

@ -12,6 +12,7 @@ exports[`Table Helpers #getRowItemDraggable it returns correctly against snapsho
"kqlQuery": "",
"name": "item1",
"queryMatch": Object {
"displayValue": "item1",
"field": "attrName",
"value": "item1",
},
@ -35,6 +36,7 @@ exports[`Table Helpers #getRowItemDraggables it returns correctly against snapsh
"kqlQuery": "",
"name": "item1",
"queryMatch": Object {
"displayValue": "item1",
"field": "attrName",
"value": "item1",
},
@ -54,6 +56,7 @@ exports[`Table Helpers #getRowItemDraggables it returns correctly against snapsh
"kqlQuery": "",
"name": "item2",
"queryMatch": Object {
"displayValue": "item2",
"field": "attrName",
"value": "item2",
},
@ -73,6 +76,7 @@ exports[`Table Helpers #getRowItemDraggables it returns correctly against snapsh
"kqlQuery": "",
"name": "item3",
"queryMatch": Object {
"displayValue": "item3",
"field": "attrName",
"value": "item3",
},

View file

@ -19,12 +19,14 @@ export const getRowItemDraggable = ({
attrName,
idPrefix,
render,
dragDisplayValue,
}: {
rowItem: string | null | undefined;
attrName: string;
idPrefix: string;
render?: (item: string) => JSX.Element;
displayCount?: number;
dragDisplayValue?: string;
maxOverflow?: number;
}): JSX.Element => {
if (rowItem != null) {
@ -39,7 +41,11 @@ export const getRowItemDraggable = ({
name: rowItem,
excluded: false,
kqlQuery: '',
queryMatch: { field: attrName, value: rowItem },
queryMatch: {
field: attrName,
value: rowItem,
displayValue: dragDisplayValue || rowItem,
},
}}
render={(dataProvider, _, snapshot) =>
snapshot.isDragging ? (
@ -62,6 +68,7 @@ export const getRowItemDraggables = ({
attrName,
idPrefix,
render,
dragDisplayValue,
displayCount = 5,
maxOverflow = 5,
}: {
@ -70,6 +77,7 @@ export const getRowItemDraggables = ({
idPrefix: string;
render?: (item: string) => JSX.Element;
displayCount?: number;
dragDisplayValue?: string;
maxOverflow?: number;
}): JSX.Element => {
if (rowItems != null && rowItems.length > 0) {
@ -87,7 +95,11 @@ export const getRowItemDraggables = ({
name: rowItem,
excluded: false,
kqlQuery: '',
queryMatch: { field: attrName, value: rowItem },
queryMatch: {
field: attrName,
value: rowItem,
displayValue: dragDisplayValue || rowItem,
},
}}
render={(dataProvider, _, snapshot) =>
snapshot.isDragging ? (