mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
## Summary * Change out event.severity for message in timeline * Fixed critical crash where you should not be able to sort on timeline columns that are not aggregatable * https://github.com/elastic/ingest-dev/issues/513 * https://github.com/elastic/ingest-dev/issues/496 Error toaster fixes: <img width="348" alt="Screen Shot 2019-06-05 at 1 59 01 PM" src="https://user-images.githubusercontent.com/1151048/58986428-97065a00-879a-11e9-8ff9-003ac29f6d9e.png"> What the timeline looks like with severity replaced with message: <img width="883" alt="Screen Shot 2019-06-05 at 1 55 19 PM" src="https://user-images.githubusercontent.com/1151048/58986459-a71e3980-879a-11e9-8144-f16f055bd53d.png"> ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] 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~~ ~~- [ ] [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:
parent
ad3620eed3
commit
391231b419
17 changed files with 252 additions and 26 deletions
|
@ -172,6 +172,7 @@ export const addFieldToTimelineColumns = ({
|
|||
example: isString(column.example) ? column.example : undefined,
|
||||
id: fieldId,
|
||||
type: column.type,
|
||||
aggregatable: column.aggregatable,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
id: timeline,
|
||||
|
|
|
@ -63,6 +63,7 @@ export const getColumnHeaderFromBrowserField = ({
|
|||
example: browserField.example != null ? `${browserField.example}` : undefined,
|
||||
id: browserField.name || '',
|
||||
type: browserField.type,
|
||||
aggregatable: browserField.aggregatable,
|
||||
width,
|
||||
});
|
||||
|
||||
|
|
|
@ -378,6 +378,7 @@ export class StatefulOpenTimelineComponent extends React.PureComponent<
|
|||
description: col.description != null ? col.description : undefined,
|
||||
example: col.example != null ? col.example : undefined,
|
||||
type: col.type != null ? col.type : undefined,
|
||||
aggregatable: col.aggregatable != null ? col.aggregatable : undefined,
|
||||
width:
|
||||
col.id === '@timestamp'
|
||||
? DEFAULT_DATE_COLUMN_MIN_WIDTH
|
||||
|
|
|
@ -390,6 +390,7 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = `
|
|||
columns={
|
||||
Array [
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Date/time when the event originated.
|
||||
|
@ -401,6 +402,7 @@ Required field for all events.",
|
|||
"width": 240,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Severity describes the severity of the event. What the different severity values mean can very different between use cases. It's up to the implementer to make sure severities are consistent across events.",
|
||||
|
@ -410,6 +412,7 @@ Required field for all events.",
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Event category.
|
||||
|
@ -420,6 +423,7 @@ This contains high-level information about the contents of the event. It is more
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "The action captured by the event.
|
||||
|
@ -430,6 +434,7 @@ This describes the information in the event. It is more specific than \`event.ca
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "host",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Name of the host.
|
||||
|
@ -440,6 +445,7 @@ It can contain what \`hostname\` returns on Unix systems, the fully qualified do
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the source.
|
||||
|
@ -450,6 +456,7 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the destination.
|
||||
|
@ -460,6 +467,7 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "user",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Short name or login of the user.",
|
||||
|
@ -469,6 +477,7 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
|
|
|
@ -397,7 +397,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
},
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"id": "event.severity",
|
||||
"id": "message",
|
||||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
|
|
|
@ -17,5 +17,6 @@ export interface ColumnHeader {
|
|||
id: ColumnId;
|
||||
placeholder?: string;
|
||||
type?: string;
|
||||
aggregatable?: boolean;
|
||||
width: number;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: 'event.severity',
|
||||
id: 'message',
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -147,11 +147,11 @@ describe('Header', () => {
|
|||
describe('onColumnSorted', () => {
|
||||
test('it invokes the onColumnSorted callback when the header is clicked', () => {
|
||||
const mockOnColumnSorted = jest.fn();
|
||||
|
||||
const headerSortable = { ...columnHeader, aggregatable: true };
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Header
|
||||
header={columnHeader}
|
||||
header={headerSortable}
|
||||
isLoading={false}
|
||||
onColumnRemoved={jest.fn()}
|
||||
onColumnResized={jest.fn()}
|
||||
|
@ -172,6 +172,81 @@ describe('Header', () => {
|
|||
sortDirection: 'asc', // (because the previous state was Direction.desc)
|
||||
});
|
||||
});
|
||||
|
||||
test('it does NOT invoke the onColumnSorted callback when the header is clicked and aggregatable is false', () => {
|
||||
const mockOnColumnSorted = jest.fn();
|
||||
const headerSortable = { ...columnHeader, aggregatable: false };
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Header
|
||||
header={headerSortable}
|
||||
isLoading={false}
|
||||
onColumnRemoved={jest.fn()}
|
||||
onColumnResized={jest.fn()}
|
||||
onColumnSorted={mockOnColumnSorted}
|
||||
sort={sort}
|
||||
timelineId={timelineId}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="header"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnColumnSorted).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('it does NOT invoke the onColumnSorted callback when the header is clicked and aggregatable is missing', () => {
|
||||
const mockOnColumnSorted = jest.fn();
|
||||
const headerSortable = { ...columnHeader };
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Header
|
||||
header={headerSortable}
|
||||
isLoading={false}
|
||||
onColumnRemoved={jest.fn()}
|
||||
onColumnResized={jest.fn()}
|
||||
onColumnSorted={mockOnColumnSorted}
|
||||
sort={sort}
|
||||
timelineId={timelineId}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="header"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnColumnSorted).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('it does NOT invoke the onColumnSorted callback when the header is clicked and aggregatable is undefined', () => {
|
||||
const mockOnColumnSorted = jest.fn();
|
||||
const headerSortable = { ...columnHeader, aggregatable: undefined };
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<Header
|
||||
header={headerSortable}
|
||||
isLoading={false}
|
||||
onColumnRemoved={jest.fn()}
|
||||
onColumnResized={jest.fn()}
|
||||
onColumnSorted={mockOnColumnSorted}
|
||||
sort={sort}
|
||||
timelineId={timelineId}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
wrapper
|
||||
.find('[data-test-subj="header"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockOnColumnSorted).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('CloseButton', () => {
|
||||
|
|
|
@ -149,7 +149,7 @@ export class Header extends React.PureComponent<Props> {
|
|||
private onClick = () => {
|
||||
const { header, isLoading, onColumnSorted, sort } = this.props;
|
||||
|
||||
if (!isLoading) {
|
||||
if (!isLoading && header.aggregatable) {
|
||||
onColumnSorted!({
|
||||
columnId: header.id,
|
||||
sortDirection: getNewSortDirectionOnClick({
|
||||
|
|
|
@ -4,6 +4,7 @@ exports[`HeaderToolTipContent it renders the expected table content 1`] = `
|
|||
<Component
|
||||
header={
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Date/time when the event originated.
|
||||
|
|
|
@ -8,7 +8,7 @@ exports[`Columns it renders the expected columns 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"id": "event.severity",
|
||||
"id": "message",
|
||||
"width": 180,
|
||||
},
|
||||
Object {
|
||||
|
|
|
@ -2,24 +2,18 @@
|
|||
|
||||
exports[`get_column_renderer renders correctly against snapshot 1`] = `
|
||||
<span>
|
||||
<Connect(DraggableWrapperComponent)
|
||||
dataProvider={
|
||||
Object {
|
||||
"and": Array [],
|
||||
"enabled": true,
|
||||
"excluded": false,
|
||||
"id": "id-timeline-column-event_severity-for-event-1-event_severity-3",
|
||||
"kqlQuery": "",
|
||||
"name": "event.severity: 3",
|
||||
"queryMatch": Object {
|
||||
"field": "event.severity",
|
||||
"operator": ":",
|
||||
"value": "3",
|
||||
},
|
||||
}
|
||||
}
|
||||
key="timeline-draggable-column-event.severity-for-event-1-event.severity--3"
|
||||
render={[Function]}
|
||||
/>
|
||||
<EuiText
|
||||
data-test-subj="draggable-content"
|
||||
key="timeline-draggable-column-event.severity-for-event-1-message--3"
|
||||
size="s"
|
||||
>
|
||||
<pure(Component)
|
||||
contextId="plain_column_renderer"
|
||||
eventId="1"
|
||||
fieldName="event.severity"
|
||||
fieldType=""
|
||||
value="3"
|
||||
/>
|
||||
</EuiText>
|
||||
</span>
|
||||
`;
|
||||
|
|
|
@ -9,7 +9,7 @@ import toJson from 'enzyme-to-json';
|
|||
import { get } from 'lodash/fp';
|
||||
import * as React from 'react';
|
||||
|
||||
import { mockTimelineData } from '../../../../mock';
|
||||
import { mockTimelineData, TestProviders } from '../../../../mock';
|
||||
import { getEmptyValue } from '../../../empty_value';
|
||||
import { FormattedFieldValue } from './formatted_field';
|
||||
|
||||
|
@ -101,4 +101,75 @@ describe('Events', () => {
|
|||
|
||||
expect(wrapper.text()).toEqual(getEmptyValue());
|
||||
});
|
||||
|
||||
test('it renders tooltip for message when it exists', () => {
|
||||
const wrapper = mount(
|
||||
<FormattedFieldValue
|
||||
eventId={mockTimelineData[0].ecs._id}
|
||||
contextId="test"
|
||||
fieldName="message"
|
||||
fieldType="text"
|
||||
value={'some message'}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="message-tool-tip"]').exists()).toEqual(true);
|
||||
});
|
||||
|
||||
test('it does NOT render a tooltip for message when it is null', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<FormattedFieldValue
|
||||
eventId={mockTimelineData[0].ecs._id}
|
||||
contextId="test"
|
||||
fieldName="message"
|
||||
fieldType="text"
|
||||
value={null}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="message-tool-tip"]').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
test('it does NOT render a tooltip for message when it is undefined', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<FormattedFieldValue
|
||||
eventId={mockTimelineData[0].ecs._id}
|
||||
contextId="test"
|
||||
fieldName="message"
|
||||
fieldType="text"
|
||||
value={undefined}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="message-tool-tip"]').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
test('it does NOT render a tooltip for message when it is an empty string', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<FormattedFieldValue
|
||||
eventId={mockTimelineData[0].ecs._id}
|
||||
contextId="test"
|
||||
fieldName="message"
|
||||
fieldType="text"
|
||||
value={''}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(wrapper.find('[data-test-subj="message-tool-tip"]').exists()).toEqual(false);
|
||||
});
|
||||
|
||||
test('it renders a message text string', () => {
|
||||
const wrapper = mount(
|
||||
<FormattedFieldValue
|
||||
eventId={mockTimelineData[0].ecs._id}
|
||||
contextId="test"
|
||||
fieldName="message"
|
||||
fieldType="text"
|
||||
value={'some message'}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.text()).toEqual('some message');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ import * as React from 'react';
|
|||
import { pure } from 'recompose';
|
||||
|
||||
import { isNumber } from 'lodash/fp';
|
||||
import { EuiToolTip, EuiFlexItem, EuiFlexGroup } from '@elastic/eui';
|
||||
import { Duration, EVENT_DURATION_FIELD_NAME } from '../../../duration';
|
||||
|
||||
import { getOrEmptyTagFromValue } from '../../../empty_value';
|
||||
|
@ -17,6 +18,7 @@ import { Port, PORT_NAMES } from '../../../port';
|
|||
|
||||
export const DATE_FIELD_TYPE = 'date';
|
||||
export const IP_FIELD_TYPE = 'ip';
|
||||
export const MESSAGE_FIELD_NAME = 'message';
|
||||
|
||||
export const FormattedFieldValue = pure<{
|
||||
eventId: string;
|
||||
|
@ -44,6 +46,25 @@ export const FormattedFieldValue = pure<{
|
|||
return (
|
||||
<Duration contextId={contextId} eventId={eventId} fieldName={fieldName} value={`${value}`} />
|
||||
);
|
||||
} else if (fieldName === MESSAGE_FIELD_NAME && value != null && value !== '') {
|
||||
return (
|
||||
<EuiToolTip
|
||||
position="left"
|
||||
data-test-subj="message-tool-tip"
|
||||
content={
|
||||
<EuiFlexGroup direction="column" gutterSize="none">
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>{fieldName}</span>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<span>{value}</span>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
}
|
||||
>
|
||||
<>{value}</>
|
||||
</EuiToolTip>
|
||||
);
|
||||
} else {
|
||||
return getOrEmptyTagFromValue(value);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import { isNumber } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
|
||||
import { EuiText } from '@elastic/eui';
|
||||
import { TimelineNonEcsData } from '../../../../graphql/types';
|
||||
import { DragEffects, DraggableWrapper } from '../../../drag_and_drop/draggable_wrapper';
|
||||
import { escapeDataProviderId } from '../../../drag_and_drop/helpers';
|
||||
|
@ -19,6 +20,7 @@ import { IP_FIELD_TYPE, FormattedFieldValue } from './formatted_field';
|
|||
import { ColumnRenderer } from './column_renderer';
|
||||
import { parseQueryValue } from './parse_query_value';
|
||||
import { parseValue } from './parse_value';
|
||||
import { TruncatableText } from '../../../truncatable_text';
|
||||
|
||||
export const dataExistsAtColumn = (columnName: string, data: TimelineNonEcsData[]): boolean =>
|
||||
data.findIndex(item => item.field === columnName) !== -1;
|
||||
|
@ -73,6 +75,45 @@ export const plainColumnRenderer: ColumnRenderer = {
|
|||
/>
|
||||
);
|
||||
}
|
||||
if (!field.aggregatable) {
|
||||
if (width != null) {
|
||||
return (
|
||||
<TruncatableText
|
||||
size="s"
|
||||
width={width}
|
||||
key={`timeline-draggable-column-${columnName}-for-event-${eventId}-${
|
||||
field.id
|
||||
}--${value}`}
|
||||
>
|
||||
<FormattedFieldValue
|
||||
eventId={eventId}
|
||||
contextId={contextId}
|
||||
fieldName={columnName}
|
||||
fieldType={field.type || ''}
|
||||
value={parseValue(value)}
|
||||
/>
|
||||
</TruncatableText>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<EuiText
|
||||
data-test-subj="draggable-content"
|
||||
size="s"
|
||||
key={`timeline-draggable-column-${columnName}-for-event-${eventId}-${
|
||||
field.id
|
||||
}--${value}`}
|
||||
>
|
||||
<FormattedFieldValue
|
||||
eventId={eventId}
|
||||
contextId={contextId}
|
||||
fieldName={columnName}
|
||||
fieldType={field.type || ''}
|
||||
value={parseValue(value)}
|
||||
/>
|
||||
</EuiText>
|
||||
);
|
||||
}
|
||||
}
|
||||
// note: we use a raw DraggableWrapper here instead of a DefaultDraggable,
|
||||
// because we pass a width to enable text truncation, and we will show empty values
|
||||
return (
|
||||
|
|
|
@ -20,6 +20,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: '2016-05-23T08:05:34.853Z',
|
||||
id: '@timestamp',
|
||||
type: 'date',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -30,6 +31,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: '7',
|
||||
id: 'event.severity',
|
||||
type: 'long',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -40,6 +42,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: 'user-management',
|
||||
id: 'event.category',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -50,6 +53,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: 'user-password-change',
|
||||
id: 'event.action',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -60,6 +64,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: '',
|
||||
id: 'host.name',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -69,6 +74,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: '',
|
||||
id: 'source.ip',
|
||||
type: 'ip',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -78,6 +84,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: '',
|
||||
id: 'destination.ip',
|
||||
type: 'ip',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -87,6 +94,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: 'albert',
|
||||
id: 'user.name',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -96,6 +104,7 @@ export const defaultHeaders: ColumnHeader[] = [
|
|||
example: 'Y-6TfmcB0WOhS6qyMv3s',
|
||||
id: '_id',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -171,6 +171,7 @@ describe('Timeline', () => {
|
|||
example: 'user-password-change',
|
||||
id: 'event.action',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
width: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue