mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
## [Security Solution] Fixes sorting issues related to unmapped fields This PR fixes the following issues related to sorting unmapped fields in timelines and the events / alerts tables: - <https://github.com/elastic/kibana/issues/129603> - <https://github.com/elastic/kibana/issues/123912> - <https://github.com/elastic/kibana/issues/131625> The `unmapped_type` property [addition](https://github.com/elastic/kibana/pull/87241/files#diff-52fd5870dcd5f783f9fc8ac3a18a8674d83ac6136e09fe0e0bcae30427d61c3fR55) to the `sort` parameter of requests was using the `type` field metadata from `BrowserFields`, but the `type` metadata (for some fields) contains the value `string`, which is not a [valid field data type](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html). The fix for the issues above: - Populates the `sort` property of requests with values from the `esTypes` `BrowserFields` metadata (instead of `type`) - The `esTypes` metadata may specify more than one field value type. When `esTypes` contains more than one type, and `keyword` is one of the types, the `sort` property of the request will prefer `keyword` over other the other types - When the field metadata has an empty `esTypes` collection, the `sort` property of the request will default to using `"unmapped_type": "keyword"` - The field type displayed in tooltips when hovering over columns in a timeline now displays values from `esTypes` instead of `type` ### Desk testing To reproduce issue <https://github.com/elastic/kibana/issues/129603> and to verify the fix: 1) Open Kibana `Dev tools` 2) Execute the following query to delete any exiting `logs-ti_test` index: ``` DELETE logs-ti_test ``` 3) Execute the following query to create an index named `logs-ti_test`, which has the following properities: - Dynamic mappings are disabled via `"dynamic": false` - It does NOT contain a mapping for `event.action` (we will sort by this field in later steps) - It contains a mapping for the non-ECS `testing` field ``` PUT logs-ti_test { "mappings": { "dynamic": false, "properties": { "@timestamp": { "type": "date" }, "event": { "properties": { "category": { "type": "keyword" }, "dataset": { "type": "keyword" }, "kind": { "type": "keyword" }, "type": { "type": "keyword" } } }, "host": { "properties": { "name": { "type": "keyword" } } }, "testing": { "type": "keyword", "ignore_above": 1024 }, "threat": { "properties": { "indicator": { "properties": { "file": { "properties": { "hash": { "properties": { "md5": { "type": "keyword" } } } } } } } } } } } } ``` 4) Execute the following query to add a new document to the `logs-ti_test` index, and note that: - It does NOT contain a `event.action` field - It contains a value for the non-ECS `testing` field ``` POST logs-ti_test/_doc/ { "@timestamp": "2022-05-12T00:00:14.725Z", "host": { "name": "foozle" }, "threat": { "indicator": { "file": { "hash": { "md5": "a4f87cbcd2a4241da77b6bf0c5d9e8553fec991f" } } } }, "event": { "kind": "enrichment", "type": "indicator", "dataset": "ti_*", "category": "threat" }, "testing": "simulated threat intel data" } ``` 5) Navigate to the Security > Hosts page 6) Select `Last 1 year` from the date picker 7) Click the `Events` tab 8) Enter the following KQL query in the search bar at the top of the page: ``` host.name: foozle ``` 9) Hover over the `foozle` entry in the `host.name` column in the Events table, and click the `Add to timeline investigation` cell action 10) Open the timeline 11) Hover over the `event.action` field **Expected result** - The tooltip displays type `keyword` for the `event.action` field **Actual result** - The tooltip displays type `string` for the `event.action` field 12) Click the `event.action` column to add a secondary sort **Expected result** - The table is sorted by `@timestamp` and `event.action` - The table contents are (still) visible **Actual result** - The table is sorted by `@timestamp` and `event.action` - The contents of the table are now empty 13) Click the timeline's `Inspect` button 14) In the `Inspect Timeline` dialog, click the `Request` tab 15) Scroll down to the `sort` property of the request **Expected result** - The `event.action` field contains a `"unmapped_type": "keyword"` property, per the example below: ```json "sort": [ { "@timestamp": { "order": "desc", "unmapped_type": "date" } }, { "event.action": { "order": "desc", "unmapped_type": "keyword" } } ], ``` **Actual result** - The request's `event.action` field contains a `"unmapped_type": "string"` property, per the example below: ```json "sort": [ { "@timestamp": { "order": "desc", "unmapped_type": "number" } }, { "event.action": { "order": "desc", "unmapped_type": "string" } } ], ``` 16) In the `Inspect Timeline` dialog, click the `Response` tab **Expected result** - The response contains `0` `failed` shards / no failures **Actual result** - The response contains failures for the `logs-ti_test` index, with the following reason: ``` "reason": "No mapper found for type [string]" ``` per the example below: ```json { "took": 1, "timed_out": false, "_shards": { "total": 4, "successful": 3, "skipped": 0, "failed": 1, "failures": [ { "shard": 0, "index": "logs-ti_test", "node": "NCRcGeDqSlKQiuPWVFvMEg", "reason": { "type": "illegal_argument_exception", "reason": "No mapper found for type [string]" } } ] }, ```
This commit is contained in:
parent
5150beeb09
commit
10dbee1716
66 changed files with 894 additions and 148 deletions
|
@ -47,6 +47,7 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest {
|
|||
|
||||
export interface TimelineRequestSortField<Field = string> extends SortField<Field> {
|
||||
type: string;
|
||||
esTypes: string[];
|
||||
}
|
||||
|
||||
export interface TimelineRequestOptionsPaginated<Field = string>
|
||||
|
|
|
@ -33,6 +33,7 @@ export type SortDirection = 'none' | 'asc' | 'desc' | Direction;
|
|||
export interface SortColumnTimeline {
|
||||
columnId: string;
|
||||
columnType: string;
|
||||
esTypes?: string[];
|
||||
sortDirection: SortDirection;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Ephemeral identifier of this agent (if one exists). This id normally changes across restarts, but \`agent.id\` does not.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500f",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -25,6 +28,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -40,6 +46,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Unique identifier of this agent (if one exists). Example: For Beats this would be beat.id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500d",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -55,6 +64,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Name of the agent. This is a name that can be given to an agent. This can be helpful if for example two Filebeat instances are running on the same host but a human readable separation is needed on which Filebeat instance data is coming from. If no name is given, the name is often left empty.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "foo",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -74,6 +86,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -87,6 +102,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -100,6 +118,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -117,6 +138,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"description": "Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -133,6 +157,7 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"indexes": Array [
|
||||
"auditbeat",
|
||||
|
@ -147,6 +172,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -166,6 +194,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Some event client addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -181,6 +212,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Bytes sent from the client to the server.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -196,6 +230,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Client domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -211,6 +248,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Country ISO code.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "CA",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -230,6 +270,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "666777888999",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -245,6 +288,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "Availability zone in which this host is running.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "us-east-1c",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -264,6 +310,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Unique container id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -279,6 +328,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Name of the image the container was built on.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -294,6 +346,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Container image tag.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -313,6 +368,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -328,6 +386,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Bytes sent from the destination to the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -343,6 +404,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Destination domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -358,6 +422,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "IP address of the destination. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -373,6 +440,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Port of the destination.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -382,7 +452,7 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
],
|
||||
"name": "destination.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -392,6 +462,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The action captured by the event. This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -413,6 +486,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. \`event.category\` represents the \\"big buckets\\" of ECS categories. For example, filtering on \`event.category:process\` yields all events relating to process activity. This field is closely related to \`event.type\`, which is used as a subcategory. This field is an array. This will allow proper categorization of some events that fall in multiple categories.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "authentication",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -434,6 +510,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "event.end contains the date when the event ended or when the activity was last observed.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -455,6 +534,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The numeric severity of the event according to your event source. What the different severity values mean can be different between sources and use cases. It's up to the implementer to make sure severities are consistent across events from the same source. The Syslog severity belongs in \`log.syslog.severity.code\`. \`event.severity\` is meant to represent the severity according to the event source (e.g. firewall, IDS). If the event source does not publish its own severity, you may optionally copy the \`log.syslog.severity.code\` to \`event.severity\`.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": 7,
|
||||
"format": "number",
|
||||
"indexes": Array [
|
||||
|
@ -480,6 +562,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "host",
|
||||
"description": "Name of the host. It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
"apm-*-transaction*",
|
||||
|
@ -548,6 +633,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "IP address of the source. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -563,6 +651,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "Port of the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -572,7 +663,7 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
],
|
||||
"name": "source.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -582,6 +673,9 @@ exports[`DragDropContextWrapper rendering it renders against the snapshot 1`] =
|
|||
"aggregatable": true,
|
||||
"category": "user",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
|
|
@ -14,6 +14,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: '@timestamp',
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
esTypes: ['date'],
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
|
|
|
@ -6,6 +6,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Ephemeral identifier of this agent (if one exists). This id normally changes across restarts, but \`agent.id\` does not.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500f",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -21,6 +24,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -36,6 +42,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Unique identifier of this agent (if one exists). Example: For Beats this would be beat.id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500d",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -51,6 +60,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Name of the agent. This is a name that can be given to an agent. This can be helpful if for example two Filebeat instances are running on the same host but a human readable separation is needed on which Filebeat instance data is coming from. If no name is given, the name is often left empty.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "foo",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -66,6 +78,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -79,6 +94,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -92,6 +110,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -105,6 +126,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"description": "Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -121,6 +145,7 @@ Array [
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"indexes": Array [
|
||||
"auditbeat",
|
||||
|
@ -135,6 +160,9 @@ Array [
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -150,6 +178,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Some event client addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -165,6 +196,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Bytes sent from the client to the server.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -180,6 +214,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Client domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -195,6 +232,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Country ISO code.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "CA",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -210,6 +250,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "666777888999",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -225,6 +268,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "Availability zone in which this host is running.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "us-east-1c",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -240,6 +286,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Unique container id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -255,6 +304,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Name of the image the container was built on.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -270,6 +322,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Container image tag.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -285,6 +340,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -300,6 +358,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Bytes sent from the destination to the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -315,6 +376,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Destination domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -330,6 +394,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "IP address of the destination. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -345,6 +412,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Port of the destination.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -354,12 +424,15 @@ Array [
|
|||
],
|
||||
"name": "destination.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "event.end contains the date when the event ended or when the activity was last observed.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -381,6 +454,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The action captured by the event. This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -402,6 +478,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. \`event.category\` represents the \\"big buckets\\" of ECS categories. For example, filtering on \`event.category:process\` yields all events relating to process activity. This field is closely related to \`event.type\`, which is used as a subcategory. This field is an array. This will allow proper categorization of some events that fall in multiple categories.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "authentication",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -423,6 +502,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The numeric severity of the event according to your event source. What the different severity values mean can be different between sources and use cases. It's up to the implementer to make sure severities are consistent across events from the same source. The Syslog severity belongs in \`log.syslog.severity.code\`. \`event.severity\` is meant to represent the severity according to the event source (e.g. firewall, IDS). If the event source does not publish its own severity, you may optionally copy the \`log.syslog.severity.code\` to \`event.severity\`.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": 7,
|
||||
"format": "number",
|
||||
"indexes": Array [
|
||||
|
@ -444,6 +526,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "host",
|
||||
"description": "Name of the host. It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
"apm-*-transaction*",
|
||||
|
@ -464,6 +549,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "IP address of the source. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -479,6 +567,9 @@ Array [
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "Port of the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -488,12 +579,15 @@ Array [
|
|||
],
|
||||
"name": "source.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"category": "user",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
|
|
@ -22,6 +22,7 @@ export const mocksSource = {
|
|||
name: '@timestamp',
|
||||
searchable: true,
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
aggregatable: true,
|
||||
readFromDocValues: true,
|
||||
},
|
||||
|
@ -31,6 +32,7 @@ export const mocksSource = {
|
|||
example: 'Y-6TfmcB0WOhS6qyMv3s',
|
||||
name: '_id',
|
||||
type: 'string',
|
||||
esTypes: [],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
|
@ -42,6 +44,7 @@ export const mocksSource = {
|
|||
example: 'Hello World',
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
format: 'string',
|
||||
|
@ -57,6 +60,7 @@ export const mocksSource = {
|
|||
name: 'agent.ephemeral_id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -68,6 +72,7 @@ export const mocksSource = {
|
|||
name: 'agent.hostname',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -80,6 +85,7 @@ export const mocksSource = {
|
|||
name: 'agent.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -92,6 +98,7 @@ export const mocksSource = {
|
|||
name: 'agent.name',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -103,6 +110,7 @@ export const mocksSource = {
|
|||
name: 'auditd.data.a0',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -114,6 +122,7 @@ export const mocksSource = {
|
|||
name: 'auditd.data.a1',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -125,6 +134,7 @@ export const mocksSource = {
|
|||
name: 'auditd.data.a2',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -137,6 +147,7 @@ export const mocksSource = {
|
|||
name: 'client.address',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -148,6 +159,7 @@ export const mocksSource = {
|
|||
name: 'client.bytes',
|
||||
searchable: true,
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -159,6 +171,7 @@ export const mocksSource = {
|
|||
name: 'client.domain',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -170,6 +183,7 @@ export const mocksSource = {
|
|||
name: 'client.geo.country_iso_code',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -182,6 +196,7 @@ export const mocksSource = {
|
|||
name: 'cloud.account.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -193,6 +208,7 @@ export const mocksSource = {
|
|||
name: 'cloud.availability_zone',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -204,6 +220,7 @@ export const mocksSource = {
|
|||
name: 'container.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -215,6 +232,7 @@ export const mocksSource = {
|
|||
name: 'container.image.name',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -226,6 +244,7 @@ export const mocksSource = {
|
|||
name: 'container.image.tag',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -238,6 +257,7 @@ export const mocksSource = {
|
|||
name: 'destination.address',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -249,6 +269,7 @@ export const mocksSource = {
|
|||
name: 'destination.bytes',
|
||||
searchable: true,
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -260,6 +281,7 @@ export const mocksSource = {
|
|||
name: 'destination.domain',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
},
|
||||
{
|
||||
|
@ -272,6 +294,7 @@ export const mocksSource = {
|
|||
name: 'destination.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
|
@ -282,7 +305,8 @@ export const mocksSource = {
|
|||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
name: 'destination.port',
|
||||
searchable: true,
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
|
@ -294,6 +318,7 @@ export const mocksSource = {
|
|||
name: 'source.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
|
@ -304,7 +329,8 @@ export const mocksSource = {
|
|||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
name: 'source.port',
|
||||
searchable: true,
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
{
|
||||
aggregatable: true,
|
||||
|
@ -317,6 +343,7 @@ export const mocksSource = {
|
|||
name: 'event.end',
|
||||
searchable: true,
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
},
|
||||
{
|
||||
category: 'event',
|
||||
|
@ -325,6 +352,7 @@ export const mocksSource = {
|
|||
example: 'user-password-change',
|
||||
name: 'event.action',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -337,6 +365,7 @@ export const mocksSource = {
|
|||
example: 'authentication',
|
||||
name: 'event.category',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -349,6 +378,7 @@ export const mocksSource = {
|
|||
example: 7,
|
||||
name: 'event.severity',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
format: 'number',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
|
@ -360,6 +390,7 @@ export const mocksSource = {
|
|||
'Name of the host. It can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.',
|
||||
name: 'host.name',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -371,6 +402,7 @@ export const mocksSource = {
|
|||
example: 'albert',
|
||||
name: 'user.name',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -459,6 +491,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'agent.ephemeral_id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'agent.hostname': {
|
||||
aggregatable: true,
|
||||
|
@ -470,6 +503,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'agent.hostname',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'agent.id': {
|
||||
aggregatable: true,
|
||||
|
@ -482,6 +516,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'agent.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'agent.name': {
|
||||
aggregatable: true,
|
||||
|
@ -494,6 +529,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'agent.name',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -509,6 +545,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'auditd.data.a0',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'auditd.data.a1': {
|
||||
aggregatable: true,
|
||||
|
@ -520,6 +557,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'auditd.data.a1',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'auditd.data.a2': {
|
||||
aggregatable: true,
|
||||
|
@ -531,6 +569,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'auditd.data.a2',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -547,6 +586,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: '@timestamp',
|
||||
searchable: true,
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
readFromDocValues: true,
|
||||
},
|
||||
_id: {
|
||||
|
@ -555,6 +595,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 'Y-6TfmcB0WOhS6qyMv3s',
|
||||
name: '_id',
|
||||
type: 'string',
|
||||
esTypes: [],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
|
@ -566,6 +607,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 'Hello World',
|
||||
name: 'message',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
searchable: true,
|
||||
aggregatable: false,
|
||||
format: 'string',
|
||||
|
@ -586,6 +628,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'client.address',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'client.bytes': {
|
||||
aggregatable: true,
|
||||
|
@ -597,6 +640,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'client.bytes',
|
||||
searchable: true,
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
'client.domain': {
|
||||
aggregatable: true,
|
||||
|
@ -608,6 +652,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'client.domain',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'client.geo.country_iso_code': {
|
||||
aggregatable: true,
|
||||
|
@ -619,6 +664,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'client.geo.country_iso_code',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -635,6 +681,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'cloud.account.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'cloud.availability_zone': {
|
||||
aggregatable: true,
|
||||
|
@ -646,6 +693,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'cloud.availability_zone',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -661,6 +709,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'container.id',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'container.image.name': {
|
||||
aggregatable: true,
|
||||
|
@ -672,6 +721,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'container.image.name',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'container.image.tag': {
|
||||
aggregatable: true,
|
||||
|
@ -683,6 +733,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'container.image.tag',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -699,6 +750,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'destination.address',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'destination.bytes': {
|
||||
aggregatable: true,
|
||||
|
@ -710,6 +762,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'destination.bytes',
|
||||
searchable: true,
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
'destination.domain': {
|
||||
aggregatable: true,
|
||||
|
@ -721,6 +774,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'destination.domain',
|
||||
searchable: true,
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
},
|
||||
'destination.ip': {
|
||||
aggregatable: true,
|
||||
|
@ -733,6 +787,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'destination.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
},
|
||||
'destination.port': {
|
||||
aggregatable: true,
|
||||
|
@ -743,7 +798,8 @@ export const mockBrowserFields: BrowserFields = {
|
|||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
name: 'destination.port',
|
||||
searchable: true,
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -759,6 +815,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'event.end',
|
||||
searchable: true,
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
aggregatable: true,
|
||||
},
|
||||
'event.action': {
|
||||
|
@ -768,6 +825,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 'user-password-change',
|
||||
name: 'event.action',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -780,6 +838,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 'authentication',
|
||||
name: 'event.category',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -792,6 +851,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 7,
|
||||
name: 'event.severity',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
format: 'number',
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
|
@ -807,6 +867,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
'Name of the host. It can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.',
|
||||
name: 'host.name',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
@ -826,6 +887,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
name: 'source.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
},
|
||||
'source.port': {
|
||||
aggregatable: true,
|
||||
|
@ -836,7 +898,8 @@ export const mockBrowserFields: BrowserFields = {
|
|||
indexes: ['auditbeat', 'filebeat', 'packetbeat'],
|
||||
name: 'source.port',
|
||||
searchable: true,
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -848,6 +911,7 @@ export const mockBrowserFields: BrowserFields = {
|
|||
example: 'albert',
|
||||
name: 'user.name',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
searchable: true,
|
||||
aggregatable: true,
|
||||
format: 'string',
|
||||
|
|
|
@ -327,7 +327,14 @@ export const mockGlobalState: State = {
|
|||
pinnedEventIds: {},
|
||||
pinnedEventsSaveObject: {},
|
||||
itemsPerPageOptions: [5, 10, 20],
|
||||
sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }],
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
isSaving: false,
|
||||
version: null,
|
||||
status: TimelineStatus.active,
|
||||
|
|
|
@ -21,6 +21,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '2016-05-23T08:05:34.853Z',
|
||||
id: '@timestamp',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -31,7 +32,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
"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.",
|
||||
example: '7',
|
||||
id: 'event.severity',
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -42,7 +44,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'Event category.\nThis contains high-level information about the contents of the event. It is more generic than `event.action`, in the sense that typically a category contains multiple actions. Warning: In future versions of ECS, we plan to provide a list of acceptable values for this field, please use with caution.',
|
||||
example: 'user-management',
|
||||
id: 'event.category',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -53,7 +56,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'The action captured by the event.\nThis describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer.',
|
||||
example: 'user-password-change',
|
||||
id: 'event.action',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -64,7 +68,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'Name of the host.\nIt can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.',
|
||||
example: '',
|
||||
id: 'host.name',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -75,6 +80,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '',
|
||||
id: 'source.ip',
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -85,6 +91,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '',
|
||||
id: 'destination.ip',
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -97,6 +104,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
format: 'bytes',
|
||||
id: 'destination.bytes',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -105,7 +113,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
description: 'Short name or login of the user.',
|
||||
example: 'albert',
|
||||
id: 'user.name',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -115,8 +124,9 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
description: 'Each document has an _id that uniquely identifies it',
|
||||
example: 'Y-6TfmcB0WOhS6qyMv3s',
|
||||
id: '_id',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
type: 'string',
|
||||
esTypes: [], // empty for _id
|
||||
aggregatable: false,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -126,7 +136,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'For log events the message field contains the log message.\nIn other use cases the message field can be used to concatenate different values which are then freely searchable. If multiple messages exist, they can be combined into one message.',
|
||||
example: 'Hello World',
|
||||
id: 'message',
|
||||
type: 'text',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
aggregatable: false,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
|
|
@ -2017,7 +2017,8 @@ export const mockTimelineModel: TimelineModel = {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
@ -2066,7 +2067,13 @@ export const mockTimelineResult = {
|
|||
};
|
||||
|
||||
const defaultTimelineColumns: CreateTimelineProps['timeline']['columns'] = [
|
||||
{ columnHeaderType: 'not-filtered', id: '@timestamp', type: 'number', initialWidth: 190 },
|
||||
{
|
||||
columnHeaderType: 'not-filtered',
|
||||
id: '@timestamp',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
initialWidth: 190,
|
||||
},
|
||||
{ columnHeaderType: 'not-filtered', id: 'message', initialWidth: 180 },
|
||||
{ columnHeaderType: 'not-filtered', id: 'event.category', initialWidth: 180 },
|
||||
{ columnHeaderType: 'not-filtered', id: 'event.action', initialWidth: 180 },
|
||||
|
@ -2136,7 +2143,14 @@ export const defaultTimelineProps: CreateTimelineProps = {
|
|||
sessionViewConfig: null,
|
||||
show: false,
|
||||
showCheckboxes: false,
|
||||
sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }],
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
status: TimelineStatus.draft,
|
||||
title: '',
|
||||
timelineType: TimelineType.default,
|
||||
|
|
|
@ -208,7 +208,8 @@ describe('alert actions', () => {
|
|||
{
|
||||
columnHeaderType: 'not-filtered',
|
||||
id: '@timestamp',
|
||||
type: 'number',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
initialWidth: 190,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -166,7 +166,8 @@ export const alertsPreviewDefaultModel: SubsetTimelineModel = {
|
|||
sort: [
|
||||
{
|
||||
columnId: 'kibana.alert.original_time',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -77,7 +77,8 @@ const columns = [
|
|||
{
|
||||
columnHeaderType: 'not-filtered',
|
||||
id: '@timestamp',
|
||||
type: 'number',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
initialWidth: 190,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -122,11 +122,18 @@ const HeaderActionsComponent: React.FC<HeaderActionProps> = ({
|
|||
dispatch(
|
||||
timelineActions.updateSort({
|
||||
id: timelineId,
|
||||
sort: cols.map(({ id, direction }) => ({
|
||||
columnId: id,
|
||||
columnType: columnHeaders.find((ch) => ch.id === id)?.type ?? 'text',
|
||||
sortDirection: direction as SortDirection,
|
||||
})),
|
||||
sort: cols.map(({ id, direction }) => {
|
||||
const columnHeader = columnHeaders.find((ch) => ch.id === id);
|
||||
const columnType = columnHeader?.type ?? '';
|
||||
const esTypes = columnHeader?.esTypes ?? [];
|
||||
|
||||
return {
|
||||
columnId: id,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection: direction as SortDirection,
|
||||
};
|
||||
}),
|
||||
})
|
||||
),
|
||||
[columnHeaders, dispatch, timelineId]
|
||||
|
|
|
@ -11,6 +11,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Ephemeral identifier of this agent (if one exists). This id normally changes across restarts, but \`agent.id\` does not.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500f",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -26,6 +29,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -41,6 +47,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Unique identifier of this agent (if one exists). Example: For Beats this would be beat.id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "8a4f500d",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -56,6 +65,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "agent",
|
||||
"description": "Name of the agent. This is a name that can be given to an agent. This can be helpful if for example two Filebeat instances are running on the same host but a human readable separation is needed on which Filebeat instance data is coming from. If no name is given, the name is often left empty.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "foo",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -75,6 +87,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -88,6 +103,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -101,6 +119,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "auditd",
|
||||
"description": null,
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -118,6 +139,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "base",
|
||||
"description": "Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -134,6 +158,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"indexes": Array [
|
||||
"auditbeat",
|
||||
|
@ -148,6 +173,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"description": "For log events the message field contains the log message, optimized for viewing in a log viewer. For structured logs without an original message field, other fields can be concatenated to form a human-readable summary of the event. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -167,6 +195,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Some event client addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -182,6 +213,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Bytes sent from the client to the server.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -197,6 +231,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Client domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -212,6 +249,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "client",
|
||||
"description": "Country ISO code.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "CA",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -231,6 +271,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "The cloud account or organization id used to identify different entities in a multi-tenant environment. Examples: AWS account id, Google Cloud ORG Id, or other unique identifier.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "666777888999",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -246,6 +289,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "cloud",
|
||||
"description": "Availability zone in which this host is running.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "us-east-1c",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -265,6 +311,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Unique container id.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -280,6 +329,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Name of the image the container was built on.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -295,6 +347,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "container",
|
||||
"description": "Container image tag.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -314,6 +369,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Some event destination addresses are defined ambiguously. The event will sometimes list an IP, a domain or a unix socket. You should always store the raw address in the \`.address\` field. Then it should be duplicated to \`.ip\` or \`.domain\`, depending on which one it is.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -329,6 +387,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Bytes sent from the destination to the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "184",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -344,6 +405,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Destination domain.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -359,6 +423,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "IP address of the destination. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -374,6 +441,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "destination",
|
||||
"description": "Port of the destination.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -383,7 +453,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
],
|
||||
"name": "destination.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -393,6 +463,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The action captured by the event. This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -414,6 +487,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "This is one of four ECS Categorization Fields, and indicates the second level in the ECS category hierarchy. \`event.category\` represents the \\"big buckets\\" of ECS categories. For example, filtering on \`event.category:process\` yields all events relating to process activity. This field is closely related to \`event.type\`, which is used as a subcategory. This field is an array. This will allow proper categorization of some events that fall in multiple categories.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "authentication",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -435,6 +511,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "event.end contains the date when the event ended or when the activity was last observed.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": null,
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -456,6 +535,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "event",
|
||||
"description": "The numeric severity of the event according to your event source. What the different severity values mean can be different between sources and use cases. It's up to the implementer to make sure severities are consistent across events from the same source. The Syslog severity belongs in \`log.syslog.severity.code\`. \`event.severity\` is meant to represent the severity according to the event source (e.g. firewall, IDS). If the event source does not publish its own severity, you may optionally copy the \`log.syslog.severity.code\` to \`event.severity\`.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": 7,
|
||||
"format": "number",
|
||||
"indexes": Array [
|
||||
|
@ -481,6 +563,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "host",
|
||||
"description": "Name of the host. It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
"apm-*-transaction*",
|
||||
|
@ -549,6 +634,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "IP address of the source. Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -564,6 +652,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "source",
|
||||
"description": "Port of the source.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "",
|
||||
"format": "",
|
||||
"indexes": Array [
|
||||
|
@ -573,7 +664,7 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
],
|
||||
"name": "source.port",
|
||||
"searchable": true,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -583,6 +674,9 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
"aggregatable": true,
|
||||
"category": "user",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"format": "string",
|
||||
"indexes": Array [
|
||||
|
@ -602,9 +696,12 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
},
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
|
@ -670,7 +767,10 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -118,6 +118,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
const onColumnSort = useCallback(
|
||||
(sortDirection: Direction) => {
|
||||
const columnId = header.id;
|
||||
const columnType = header.type ?? '';
|
||||
const esTypes = header.esTypes ?? [];
|
||||
const headerIndex = sort.findIndex((col) => col.columnId === columnId);
|
||||
const newSort =
|
||||
headerIndex === -1
|
||||
|
@ -125,7 +127,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
...sort,
|
||||
{
|
||||
columnId,
|
||||
columnType: `${header.type}`,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
]
|
||||
|
@ -133,7 +136,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
...sort.slice(0, headerIndex),
|
||||
{
|
||||
columnId,
|
||||
columnType: `${header.type}`,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
...sort.slice(headerIndex + 1),
|
||||
|
|
|
@ -15,8 +15,9 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: '@timestamp',
|
||||
type: 'number',
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
esTypes: ['date'],
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
|
|
|
@ -6,9 +6,12 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
header={
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
}
|
||||
}
|
||||
isLoading={false}
|
||||
|
@ -19,7 +22,10 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
@ -29,9 +35,12 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
header={
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
}
|
||||
}
|
||||
isLoading={false}
|
||||
|
@ -40,7 +49,10 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
@ -51,9 +63,12 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
header={
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
}
|
||||
}
|
||||
onFilterChange={[Function]}
|
||||
|
|
|
@ -43,7 +43,8 @@ describe('Header', () => {
|
|||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
columnType: columnHeader.type ?? '',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
@ -183,6 +184,7 @@ describe('Header', () => {
|
|||
{
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.asc, // (because the previous state was Direction.desc)
|
||||
},
|
||||
],
|
||||
|
@ -251,6 +253,7 @@ describe('Header', () => {
|
|||
{
|
||||
columnId: 'differentSocks',
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
@ -264,6 +267,7 @@ describe('Header', () => {
|
|||
const sortDescending: Sort = {
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.desc,
|
||||
};
|
||||
|
||||
|
@ -274,6 +278,7 @@ describe('Header', () => {
|
|||
const sortAscending: Sort = {
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.asc,
|
||||
};
|
||||
|
||||
|
@ -284,6 +289,7 @@ describe('Header', () => {
|
|||
const sortNone: Sort = {
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: 'none',
|
||||
};
|
||||
|
||||
|
@ -297,6 +303,7 @@ describe('Header', () => {
|
|||
{
|
||||
columnId: columnHeader.id,
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
@ -314,6 +321,7 @@ describe('Header', () => {
|
|||
{
|
||||
columnId: 'someOtherColumn',
|
||||
columnType: columnHeader.type ?? 'number',
|
||||
esTypes: columnHeader.esTypes ?? [],
|
||||
sortDirection: 'none',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -43,7 +43,8 @@ export const HeaderComponent: React.FC<Props> = ({
|
|||
|
||||
const onColumnSort = useCallback(() => {
|
||||
const columnId = header.id;
|
||||
const columnType = header.type ?? 'text';
|
||||
const columnType = header.type ?? '';
|
||||
const esTypes = header.esTypes ?? [];
|
||||
const sortDirection = getNewSortDirectionOnClick({
|
||||
clickedHeader: header,
|
||||
currentSort: sort,
|
||||
|
@ -56,6 +57,7 @@ export const HeaderComponent: React.FC<Props> = ({
|
|||
{
|
||||
columnId,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
];
|
||||
|
@ -65,6 +67,7 @@ export const HeaderComponent: React.FC<Props> = ({
|
|||
{
|
||||
columnId,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
...sort.slice(headerIndex + 1),
|
||||
|
|
|
@ -40,11 +40,12 @@ exports[`HeaderToolTipContent it renders the expected table content 1`] = `
|
|||
data-test-subj="type-icon"
|
||||
type="clock"
|
||||
/>
|
||||
<span
|
||||
data-test-subj="type-value"
|
||||
<EuiBadge
|
||||
data-test-subj="type-value-date"
|
||||
key="date"
|
||||
>
|
||||
date
|
||||
</span>
|
||||
</EuiBadge>
|
||||
</ToolTipTableValue>
|
||||
</P>
|
||||
<P>
|
||||
|
|
|
@ -42,7 +42,24 @@ describe('HeaderToolTipContent', () => {
|
|||
test('it renders the type of the field', () => {
|
||||
const wrapper = mount(<HeaderToolTipContent header={header} />);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="type-value"]').first().text()).toEqual(header.type);
|
||||
expect(
|
||||
wrapper
|
||||
.find(`[data-test-subj="type-value-${header.esTypes?.at(0)}"]`)
|
||||
.first()
|
||||
.text()
|
||||
).toEqual(header.esTypes?.at(0));
|
||||
});
|
||||
|
||||
test('it renders multiple `esTypes`', () => {
|
||||
const hasMultipleTypes = { ...header, esTypes: ['long', 'date'] };
|
||||
|
||||
const wrapper = mount(<HeaderToolTipContent header={hasMultipleTypes} />);
|
||||
|
||||
hasMultipleTypes.esTypes.forEach((esType) => {
|
||||
expect(wrapper.find(`[data-test-subj="type-value-${esType}"]`).first().text()).toEqual(
|
||||
esType
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test('it renders the description of the field', () => {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { EuiIcon } from '@elastic/eui';
|
||||
import { EuiIcon, EuiBadge } from '@elastic/eui';
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
@ -29,6 +29,7 @@ P.displayName = 'P';
|
|||
const ToolTipTableMetadata = styled.span`
|
||||
margin-right: 5px;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
`;
|
||||
ToolTipTableMetadata.displayName = 'ToolTipTableMetadata';
|
||||
|
||||
|
@ -62,7 +63,11 @@ export const HeaderToolTipContent = React.memo<{ header: ColumnHeaderOptions }>(
|
|||
</ToolTipTableMetadata>
|
||||
<ToolTipTableValue>
|
||||
<IconType data-test-subj="type-icon" type={getIconFromType(header.type)} />
|
||||
<span data-test-subj="type-value">{header.type}</span>
|
||||
{header.esTypes?.map((esType) => (
|
||||
<EuiBadge data-test-subj={`type-value-${esType}`} key={esType}>
|
||||
{esType}
|
||||
</EuiBadge>
|
||||
))}
|
||||
</ToolTipTableValue>
|
||||
</P>
|
||||
{!isEmpty(header.description) && (
|
||||
|
|
|
@ -40,6 +40,7 @@ describe('helpers', () => {
|
|||
readFromDocValues: true,
|
||||
searchable: true,
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
initialWidth: 190,
|
||||
},
|
||||
{
|
||||
|
@ -54,6 +55,7 @@ describe('helpers', () => {
|
|||
name: 'source.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
initialWidth: 180,
|
||||
},
|
||||
{
|
||||
|
@ -69,6 +71,7 @@ describe('helpers', () => {
|
|||
name: 'destination.ip',
|
||||
searchable: true,
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
initialWidth: 180,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -55,7 +55,8 @@ describe('ColumnHeaders', () => {
|
|||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
@ -112,12 +113,14 @@ describe('ColumnHeaders', () => {
|
|||
let mockSort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
{
|
||||
columnId: 'host.name',
|
||||
columnType: 'text',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
];
|
||||
|
@ -132,12 +135,14 @@ describe('ColumnHeaders', () => {
|
|||
mockSort = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
{
|
||||
columnId: 'host.name',
|
||||
columnType: 'text',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
];
|
||||
|
@ -156,21 +161,29 @@ describe('ColumnHeaders', () => {
|
|||
.find('[data-test-subj="header-event.category"] [data-test-subj="header-sort-button"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
timelineActions.updateSort({
|
||||
id: timelineId,
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
{
|
||||
columnId: 'host.name',
|
||||
columnType: 'text',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
{ columnId: 'event.category', columnType: 'text', sortDirection: Direction.desc },
|
||||
{
|
||||
columnId: 'event.category',
|
||||
columnType: '',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
@ -195,10 +208,16 @@ describe('ColumnHeaders', () => {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
{
|
||||
columnId: 'host.name',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
{ columnId: 'host.name', columnType: 'text', sortDirection: Direction.asc },
|
||||
],
|
||||
})
|
||||
);
|
||||
|
@ -221,16 +240,23 @@ describe('ColumnHeaders', () => {
|
|||
.find('[data-test-subj="header-host.name"] [data-test-subj="header-sort-button"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
|
||||
expect(mockDispatch).toHaveBeenCalledWith(
|
||||
timelineActions.updateSort({
|
||||
id: timelineId,
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
{
|
||||
columnId: 'host.name',
|
||||
columnType: '',
|
||||
esTypes: [],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
{ columnId: 'host.name', columnType: 'text', sortDirection: Direction.desc },
|
||||
],
|
||||
})
|
||||
);
|
||||
|
|
|
@ -71,7 +71,8 @@ jest.mock('../../../../common/lib/kibana', () => {
|
|||
const mockSort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -7,7 +7,7 @@ exports[`plain_column_renderer rendering renders correctly against snapshot 1`]
|
|||
eventId="1"
|
||||
fieldFormat=""
|
||||
fieldName="event.category"
|
||||
fieldType="keyword"
|
||||
fieldType="string"
|
||||
isAggregatable={true}
|
||||
isDraggable={true}
|
||||
key="plain-column-renderer-formatted-field-value-test-event.category-1-event.category-Access-0"
|
||||
|
|
|
@ -12,6 +12,9 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = `
|
|||
"description": "Date/time when the event originated.
|
||||
For log events this is the date/time when the event was generated, and not when it was read.
|
||||
Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
|
@ -22,10 +25,13 @@ Required field for all events.",
|
|||
"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.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "7",
|
||||
"id": "event.severity",
|
||||
"initialWidth": 180,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -33,10 +39,13 @@ Required field for all events.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Event category.
|
||||
This contains high-level information about the contents of the event. It is more generic than \`event.action\`, in the sense that typically a category contains multiple actions. Warning: In future versions of ECS, we plan to provide a list of acceptable values for this field, please use with caution.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-management",
|
||||
"id": "event.category",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -44,10 +53,13 @@ This contains high-level information about the contents of the event. It is more
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "The action captured by the event.
|
||||
This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"id": "event.action",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -55,10 +67,13 @@ This describes the information in the event. It is more specific than \`event.ca
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Name of the host.
|
||||
It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "",
|
||||
"id": "host.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -66,6 +81,9 @@ It can contain what \`hostname\` returns on Unix systems, the fully qualified do
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the source.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "source.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -77,6 +95,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the destination.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "destination.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -87,6 +108,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "destination",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Bytes sent from the source to the destination",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "123",
|
||||
"format": "bytes",
|
||||
"id": "destination.bytes",
|
||||
|
@ -98,20 +122,24 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "user",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"id": "user.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"id": "_id",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": false,
|
||||
|
@ -119,10 +147,13 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "For log events the message field contains the log message.
|
||||
In other use cases the message field can be used to concatenate different values which are then freely searchable. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"id": "message",
|
||||
"initialWidth": 180,
|
||||
"type": "text",
|
||||
"type": "string",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@ exports[`PinnedTabContent rendering renders correctly against snapshot 1`] = `
|
|||
"description": "Date/time when the event originated.
|
||||
For log events this is the date/time when the event was generated, and not when it was read.
|
||||
Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
|
@ -21,10 +24,13 @@ Required field for all events.",
|
|||
"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.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "7",
|
||||
"id": "event.severity",
|
||||
"initialWidth": 180,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -32,10 +38,13 @@ Required field for all events.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Event category.
|
||||
This contains high-level information about the contents of the event. It is more generic than \`event.action\`, in the sense that typically a category contains multiple actions. Warning: In future versions of ECS, we plan to provide a list of acceptable values for this field, please use with caution.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-management",
|
||||
"id": "event.category",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -43,10 +52,13 @@ This contains high-level information about the contents of the event. It is more
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "The action captured by the event.
|
||||
This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"id": "event.action",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -54,10 +66,13 @@ This describes the information in the event. It is more specific than \`event.ca
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Name of the host.
|
||||
It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "",
|
||||
"id": "host.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -65,6 +80,9 @@ It can contain what \`hostname\` returns on Unix systems, the fully qualified do
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the source.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "source.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -76,6 +94,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the destination.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "destination.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -86,6 +107,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "destination",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Bytes sent from the source to the destination",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "123",
|
||||
"format": "bytes",
|
||||
"id": "destination.bytes",
|
||||
|
@ -97,20 +121,24 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "user",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"id": "user.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"id": "_id",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": false,
|
||||
|
@ -118,10 +146,13 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "For log events the message field contains the log message.
|
||||
In other use cases the message field can be used to concatenate different values which are then freely searchable. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"id": "message",
|
||||
"initialWidth": 180,
|
||||
"type": "text",
|
||||
"type": "string",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -1125,7 +1156,10 @@ In other use cases the message field can be used to concatenate different values
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -82,7 +82,8 @@ describe('PinnedTabContent', () => {
|
|||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -174,10 +174,11 @@ export const PinnedTabContentComponent: React.FC<Props> = ({
|
|||
|
||||
const timelineQuerySortField = useMemo(
|
||||
() =>
|
||||
sort.map(({ columnId, columnType, sortDirection }) => ({
|
||||
sort.map(({ columnId, columnType, esTypes, sortDirection }) => ({
|
||||
field: columnId,
|
||||
type: columnType,
|
||||
direction: sortDirection as Direction,
|
||||
esTypes: esTypes ?? [],
|
||||
})),
|
||||
[sort]
|
||||
);
|
||||
|
|
|
@ -12,6 +12,9 @@ exports[`Timeline rendering renders correctly against snapshot 1`] = `
|
|||
"description": "Date/time when the event originated.
|
||||
For log events this is the date/time when the event was generated, and not when it was read.
|
||||
Required field for all events.",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"example": "2016-05-23T08:05:34.853Z",
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
|
@ -22,10 +25,13 @@ Required field for all events.",
|
|||
"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.",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "7",
|
||||
"id": "event.severity",
|
||||
"initialWidth": 180,
|
||||
"type": "long",
|
||||
"type": "number",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -33,10 +39,13 @@ Required field for all events.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Event category.
|
||||
This contains high-level information about the contents of the event. It is more generic than \`event.action\`, in the sense that typically a category contains multiple actions. Warning: In future versions of ECS, we plan to provide a list of acceptable values for this field, please use with caution.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-management",
|
||||
"id": "event.category",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -44,10 +53,13 @@ This contains high-level information about the contents of the event. It is more
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "The action captured by the event.
|
||||
This describes the information in the event. It is more specific than \`event.category\`. Examples are \`group-add\`, \`process-started\`, \`file-created\`. The value is normally defined by the implementer.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "user-password-change",
|
||||
"id": "event.action",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -55,10 +67,13 @@ This describes the information in the event. It is more specific than \`event.ca
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "Name of the host.
|
||||
It can contain what \`hostname\` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "",
|
||||
"id": "host.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
|
@ -66,6 +81,9 @@ It can contain what \`hostname\` returns on Unix systems, the fully qualified do
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the source.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "source.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -77,6 +95,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "IP address of the destination.
|
||||
Can be one or multiple IPv4 or IPv6 addresses.",
|
||||
"esTypes": Array [
|
||||
"ip",
|
||||
],
|
||||
"example": "",
|
||||
"id": "destination.ip",
|
||||
"initialWidth": 180,
|
||||
|
@ -87,6 +108,9 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "destination",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Bytes sent from the source to the destination",
|
||||
"esTypes": Array [
|
||||
"long",
|
||||
],
|
||||
"example": "123",
|
||||
"format": "bytes",
|
||||
"id": "destination.bytes",
|
||||
|
@ -98,20 +122,24 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"category": "user",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Short name or login of the user.",
|
||||
"esTypes": Array [
|
||||
"keyword",
|
||||
],
|
||||
"example": "albert",
|
||||
"id": "user.name",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": true,
|
||||
"aggregatable": false,
|
||||
"category": "base",
|
||||
"columnHeaderType": "not-filtered",
|
||||
"description": "Each document has an _id that uniquely identifies it",
|
||||
"esTypes": Array [],
|
||||
"example": "Y-6TfmcB0WOhS6qyMv3s",
|
||||
"id": "_id",
|
||||
"initialWidth": 180,
|
||||
"type": "keyword",
|
||||
"type": "string",
|
||||
},
|
||||
Object {
|
||||
"aggregatable": false,
|
||||
|
@ -119,10 +147,13 @@ Can be one or multiple IPv4 or IPv6 addresses.",
|
|||
"columnHeaderType": "not-filtered",
|
||||
"description": "For log events the message field contains the log message.
|
||||
In other use cases the message field can be used to concatenate different values which are then freely searchable. If multiple messages exist, they can be combined into one message.",
|
||||
"esTypes": Array [
|
||||
"text",
|
||||
],
|
||||
"example": "Hello World",
|
||||
"id": "message",
|
||||
"initialWidth": 180,
|
||||
"type": "text",
|
||||
"type": "string",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -1267,7 +1298,10 @@ In other use cases the message field can be used to concatenate different values
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -95,7 +95,8 @@ describe('Timeline', () => {
|
|||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -266,9 +266,10 @@ export const QueryTabContentComponent: React.FC<Props> = ({
|
|||
return [...columnFields, ...requiredFieldsForActions];
|
||||
};
|
||||
|
||||
const timelineQuerySortField = sort.map(({ columnId, columnType, sortDirection }) => ({
|
||||
const timelineQuerySortField = sort.map(({ columnId, columnType, esTypes, sortDirection }) => ({
|
||||
field: columnId,
|
||||
direction: sortDirection as Direction,
|
||||
esTypes: esTypes ?? [],
|
||||
type: columnType,
|
||||
}));
|
||||
|
||||
|
|
|
@ -100,11 +100,12 @@ const getTimelineEvents = (timelineEdges: TimelineEdges[]): TimelineItem[] =>
|
|||
timelineEdges.map((e: TimelineEdges) => e.node);
|
||||
|
||||
const ID = 'timelineEventsQuery';
|
||||
export const initSortDefault = [
|
||||
export const initSortDefault: TimelineRequestSortField[] = [
|
||||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.asc,
|
||||
type: 'number',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ export const timelineDefaults: SubsetTimelineModel &
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -162,7 +162,14 @@ describe('Epic Timeline', () => {
|
|||
sessionViewConfig: null,
|
||||
show: true,
|
||||
showCheckboxes: false,
|
||||
sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }],
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
status: TimelineStatus.active,
|
||||
version: 'WzM4LDFd',
|
||||
id: '11169110-fc22-11e9-8ca9-072f15ce2685',
|
||||
|
@ -304,7 +311,8 @@ describe('Epic Timeline', () => {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -368,7 +368,7 @@ export const convertTimelineAsInput = (
|
|||
return set(
|
||||
key,
|
||||
get(key, timeline).map((col: ColumnHeaderOptions) =>
|
||||
omit(['initialWidth', 'width', '__typename'], col)
|
||||
omit(['initialWidth', 'width', '__typename', 'esTypes'], col)
|
||||
),
|
||||
acc
|
||||
);
|
||||
|
|
|
@ -58,7 +58,8 @@ describe('epicLocalStorage', () => {
|
|||
const sort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
@ -161,6 +162,7 @@ describe('epicLocalStorage', () => {
|
|||
{
|
||||
columnId: 'event.severity',
|
||||
columnType: 'number',
|
||||
esTypes: ['long'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -129,7 +129,8 @@ const basicTimeline: TimelineModel = {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
@ -958,6 +959,7 @@ describe('Timeline', () => {
|
|||
{
|
||||
columnId: 'some column',
|
||||
columnType: 'text',
|
||||
esTypes: ['keyword'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
@ -970,7 +972,12 @@ describe('Timeline', () => {
|
|||
|
||||
test('should update the sort attribute', () => {
|
||||
expect(update.foo.sort).toEqual([
|
||||
{ columnId: 'some column', columnType: 'text', sortDirection: Direction.desc },
|
||||
{
|
||||
columnId: 'some column',
|
||||
columnType: 'text',
|
||||
esTypes: ['keyword'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -70,6 +70,7 @@ export interface BrowserField {
|
|||
name: string;
|
||||
searchable: boolean;
|
||||
type: string;
|
||||
esTypes?: string[];
|
||||
subType?: IFieldSubType;
|
||||
readFromDocValues: boolean;
|
||||
runtimeField?: RuntimeField;
|
||||
|
|
|
@ -48,6 +48,7 @@ export interface TimelineRequestBasicOptions extends IEsSearchRequest {
|
|||
}
|
||||
|
||||
export interface TimelineRequestSortField<Field = string> extends SortField<Field> {
|
||||
esTypes: string[];
|
||||
type: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ export type ColumnHeaderOptions = Pick<
|
|||
category?: string;
|
||||
columnHeaderType: ColumnHeaderType;
|
||||
description?: string | null;
|
||||
esTypes?: string[];
|
||||
example?: string | number | null;
|
||||
format?: string;
|
||||
linkField?: string;
|
||||
|
|
|
@ -34,6 +34,7 @@ export type SortDirection = 'none' | 'asc' | 'desc' | Direction;
|
|||
export interface SortColumnTimeline {
|
||||
columnId: string;
|
||||
columnType: string;
|
||||
esTypes?: string[];
|
||||
sortDirection: SortDirection;
|
||||
}
|
||||
|
||||
|
|
|
@ -596,9 +596,12 @@ exports[`ColumnHeaders rendering renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
},
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
|
|
|
@ -119,6 +119,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
const onColumnSort = useCallback(
|
||||
(sortDirection: Direction) => {
|
||||
const columnId = header.id;
|
||||
const columnType = header.type ?? '';
|
||||
const esTypes = header.esTypes ?? [];
|
||||
const headerIndex = sort.findIndex((col) => col.columnId === columnId);
|
||||
const newSort =
|
||||
headerIndex === -1
|
||||
|
@ -126,7 +128,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
...sort,
|
||||
{
|
||||
columnId,
|
||||
columnType: `${header.type}`,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
]
|
||||
|
@ -134,7 +137,8 @@ const ColumnHeaderComponent: React.FC<ColumneHeaderProps> = ({
|
|||
...sort.slice(0, headerIndex),
|
||||
{
|
||||
columnId,
|
||||
columnType: `${header.type}`,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection,
|
||||
},
|
||||
...sort.slice(headerIndex + 1),
|
||||
|
|
|
@ -14,8 +14,9 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: '@timestamp',
|
||||
type: 'number',
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
esTypes: ['date'],
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
|
|
|
@ -6,9 +6,12 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
header={
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
}
|
||||
}
|
||||
isLoading={false}
|
||||
|
@ -19,7 +22,7 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
@ -29,9 +32,12 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
header={
|
||||
Object {
|
||||
"columnHeaderType": "not-filtered",
|
||||
"esTypes": Array [
|
||||
"date",
|
||||
],
|
||||
"id": "@timestamp",
|
||||
"initialWidth": 190,
|
||||
"type": "number",
|
||||
"type": "date",
|
||||
}
|
||||
}
|
||||
isLoading={false}
|
||||
|
@ -40,7 +46,7 @@ exports[`Header renders correctly against snapshot 1`] = `
|
|||
Array [
|
||||
Object {
|
||||
"columnId": "@timestamp",
|
||||
"columnType": "number",
|
||||
"columnType": "date",
|
||||
"sortDirection": "desc",
|
||||
},
|
||||
]
|
||||
|
|
|
@ -209,6 +209,7 @@ describe('helpers', () => {
|
|||
defaultSortDirection,
|
||||
description:
|
||||
'Date/time when the event originated. For log events this is the date/time when the event was generated, and not when it was read. Required field for all events.',
|
||||
esTypes: ['date'],
|
||||
example: '2016-05-23T08:05:34.853Z',
|
||||
format: '',
|
||||
id: '@timestamp',
|
||||
|
|
|
@ -245,7 +245,7 @@ describe('ColumnHeaders', () => {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
sortDirection: Direction.asc,
|
||||
},
|
||||
{ columnId: 'host.name', columnType: 'text', sortDirection: Direction.asc },
|
||||
|
|
|
@ -260,6 +260,7 @@ describe('helpers', () => {
|
|||
initialWidth: 176,
|
||||
category: 'kibana',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
aggregatable: true,
|
||||
actions: {
|
||||
showSortAsc: {
|
||||
|
@ -291,12 +292,22 @@ describe('helpers', () => {
|
|||
|
||||
test('it returns the expected results when each column has a corresponding entry in `columnHeaders`', () => {
|
||||
expect(mapSortingColumns({ columns, columnHeaders })).toEqual([
|
||||
{ columnId: 'kibana.rac.alert.status', columnType: 'string', sortDirection: 'asc' },
|
||||
{ columnId: 'kibana.rac.alert.start', columnType: 'date', sortDirection: 'desc' },
|
||||
{
|
||||
columnId: 'kibana.rac.alert.status',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: 'asc',
|
||||
},
|
||||
{
|
||||
columnId: 'kibana.rac.alert.start',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('it defaults to a `columnType` of `text` when a column does NOT has a corresponding entry in `columnHeaders`', () => {
|
||||
test('it defaults to a `columnType` of empty string when a column does NOT has a corresponding entry in `columnHeaders`', () => {
|
||||
const withUnknownColumn: Array<{
|
||||
id: string;
|
||||
direction: 'asc' | 'desc';
|
||||
|
@ -316,11 +327,22 @@ describe('helpers', () => {
|
|||
];
|
||||
|
||||
expect(mapSortingColumns({ columns: withUnknownColumn, columnHeaders })).toEqual([
|
||||
{ columnId: 'kibana.rac.alert.status', columnType: 'string', sortDirection: 'asc' },
|
||||
{ columnId: 'kibana.rac.alert.start', columnType: 'date', sortDirection: 'desc' },
|
||||
{
|
||||
columnId: 'kibana.rac.alert.status',
|
||||
columnType: 'string',
|
||||
esTypes: [],
|
||||
sortDirection: 'asc',
|
||||
},
|
||||
{
|
||||
columnId: 'kibana.rac.alert.start',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
{
|
||||
columnId: 'unknown',
|
||||
columnType: 'text', // <-- mapped to the default
|
||||
columnType: '', // <-- mapped to the default
|
||||
esTypes: [], // <-- mapped to the default
|
||||
sortDirection: 'asc',
|
||||
},
|
||||
]);
|
||||
|
|
|
@ -123,11 +123,18 @@ export const mapSortingColumns = ({
|
|||
direction: 'asc' | 'desc';
|
||||
}>;
|
||||
}): SortColumnTimeline[] =>
|
||||
columns.map(({ id, direction }) => ({
|
||||
columnId: id,
|
||||
columnType: columnHeaders.find((ch) => ch.id === id)?.type ?? 'text',
|
||||
sortDirection: direction,
|
||||
}));
|
||||
columns.map(({ id, direction }) => {
|
||||
const columnHeader = columnHeaders.find((ch) => ch.id === id);
|
||||
const columnType = columnHeader?.type ?? '';
|
||||
const esTypes = columnHeader?.esTypes ?? [];
|
||||
|
||||
return {
|
||||
columnId: id,
|
||||
columnType,
|
||||
esTypes,
|
||||
sortDirection: direction,
|
||||
};
|
||||
});
|
||||
|
||||
export const allowSorting = ({
|
||||
browserField,
|
||||
|
|
|
@ -23,7 +23,8 @@ import { defaultColumnHeaderType } from '../../../store/t_grid/defaults';
|
|||
const mockSort: Sort[] = [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -226,10 +226,11 @@ const TGridIntegratedComponent: React.FC<TGridIntegratedProps> = ({
|
|||
|
||||
const sortField = useMemo(
|
||||
() =>
|
||||
sort.map(({ columnId, columnType, sortDirection }) => ({
|
||||
sort.map(({ columnId, columnType, esTypes, sortDirection }) => ({
|
||||
field: columnId,
|
||||
type: columnType,
|
||||
direction: sortDirection as Direction,
|
||||
esTypes: esTypes ?? [],
|
||||
})),
|
||||
[sort]
|
||||
);
|
||||
|
|
|
@ -201,10 +201,11 @@ const TGridStandaloneComponent: React.FC<TGridStandaloneProps> = ({
|
|||
|
||||
const sortField = useMemo(
|
||||
() =>
|
||||
sortStore.map(({ columnId, columnType, sortDirection }) => ({
|
||||
sortStore.map(({ columnId, columnType, esTypes, sortDirection }) => ({
|
||||
field: columnId,
|
||||
type: columnType,
|
||||
direction: sortDirection as Direction,
|
||||
esTypes: esTypes ?? [],
|
||||
})),
|
||||
[sortStore]
|
||||
);
|
||||
|
|
|
@ -110,9 +110,10 @@ const getInspectResponse = <T extends TimelineFactoryQueryTypes>(
|
|||
const ID = 'timelineEventsQuery';
|
||||
export const initSortDefault = [
|
||||
{
|
||||
direction: Direction.desc,
|
||||
esTypes: ['date'],
|
||||
field: '@timestamp',
|
||||
direction: Direction.asc,
|
||||
type: 'number',
|
||||
type: 'date',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -40,7 +40,14 @@ export const mockGlobalState: TimelineState = {
|
|||
itemsPerPageOptions: [5, 10, 20],
|
||||
loadingEventIds: [],
|
||||
showCheckboxes: false,
|
||||
sort: [{ columnId: '@timestamp', columnType: 'number', sortDirection: Direction.desc }],
|
||||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
selectedEventIds: {},
|
||||
savedObjectId: null,
|
||||
version: null,
|
||||
|
|
|
@ -21,6 +21,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '2016-05-23T08:05:34.853Z',
|
||||
id: '@timestamp',
|
||||
type: 'date',
|
||||
esTypes: ['date'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -31,7 +32,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
"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.",
|
||||
example: '7',
|
||||
id: 'event.severity',
|
||||
type: 'long',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -42,7 +44,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'Event category.\nThis contains high-level information about the contents of the event. It is more generic than `event.action`, in the sense that typically a category contains multiple actions. Warning: In future versions of ECS, we plan to provide a list of acceptable values for this field, please use with caution.',
|
||||
example: 'user-management',
|
||||
id: 'event.category',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -53,7 +56,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'The action captured by the event.\nThis describes the information in the event. It is more specific than `event.category`. Examples are `group-add`, `process-started`, `file-created`. The value is normally defined by the implementer.',
|
||||
example: 'user-password-change',
|
||||
id: 'event.action',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -64,7 +68,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'Name of the host.\nIt can contain what `hostname` returns on Unix systems, the fully qualified domain name, or a name specified by the user. The sender decides which value to use.',
|
||||
example: '',
|
||||
id: 'host.name',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -75,6 +80,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '',
|
||||
id: 'source.ip',
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -85,6 +91,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
example: '',
|
||||
id: 'destination.ip',
|
||||
type: 'ip',
|
||||
esTypes: ['ip'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -97,6 +104,7 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
format: 'bytes',
|
||||
id: 'destination.bytes',
|
||||
type: 'number',
|
||||
esTypes: ['long'],
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -105,7 +113,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
description: 'Short name or login of the user.',
|
||||
example: 'albert',
|
||||
id: 'user.name',
|
||||
type: 'keyword',
|
||||
type: 'string',
|
||||
esTypes: ['keyword'],
|
||||
aggregatable: true,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
@ -115,8 +124,9 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
description: 'Each document has an _id that uniquely identifies it',
|
||||
example: 'Y-6TfmcB0WOhS6qyMv3s',
|
||||
id: '_id',
|
||||
type: 'keyword',
|
||||
aggregatable: true,
|
||||
type: 'string',
|
||||
esTypes: [], // empty for _id
|
||||
aggregatable: false,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
{
|
||||
|
@ -126,7 +136,8 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
'For log events the message field contains the log message.\nIn other use cases the message field can be used to concatenate different values which are then freely searchable. If multiple messages exist, they can be combined into one message.',
|
||||
example: 'Hello World',
|
||||
id: 'message',
|
||||
type: 'text',
|
||||
type: 'string',
|
||||
esTypes: ['text'],
|
||||
aggregatable: false,
|
||||
initialWidth: DEFAULT_COLUMN_MIN_WIDTH,
|
||||
},
|
||||
|
|
|
@ -1580,7 +1580,8 @@ export const mockTgridModel: TGridModel = {
|
|||
sort: [
|
||||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'number',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -123,6 +123,7 @@ export const tGridIntegratedProps: TGridIntegratedProps = {
|
|||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: 'desc',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -20,8 +20,9 @@ export const defaultHeaders: ColumnHeaderOptions[] = [
|
|||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
id: '@timestamp',
|
||||
type: 'number',
|
||||
initialWidth: DEFAULT_DATE_COLUMN_MIN_WIDTH,
|
||||
esTypes: ['date'],
|
||||
type: 'date',
|
||||
},
|
||||
{
|
||||
columnHeaderType: defaultColumnHeaderType,
|
||||
|
@ -84,6 +85,7 @@ export const tGridDefaults: SubsetTGridModel = {
|
|||
{
|
||||
columnId: '@timestamp',
|
||||
columnType: 'date',
|
||||
esTypes: ['date'],
|
||||
sortDirection: Direction.desc,
|
||||
},
|
||||
],
|
||||
|
|
|
@ -24,7 +24,7 @@ const defaultTimelineById = {
|
|||
describe('setInitializeTgridSettings', () => {
|
||||
test('it returns the expected sort when tGridSettingsProps has an override', () => {
|
||||
const sort: SortColumnTimeline[] = [
|
||||
{ columnId: 'foozle', columnType: 'date', sortDirection: 'asc' },
|
||||
{ columnId: 'foozle', columnType: 'date', esTypes: ['date'], sortDirection: 'asc' },
|
||||
];
|
||||
|
||||
const tGridSettingsProps: Partial<TGridModelSettings> = {
|
||||
|
|
|
@ -35,9 +35,10 @@ describe('Search Strategy EQL helper', () => {
|
|||
pagination: { activePage: 0, querySize: 25 },
|
||||
sort: [
|
||||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.desc,
|
||||
type: 'number',
|
||||
esTypes: ['date'],
|
||||
field: '@timestamp',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
timerange: {
|
||||
|
@ -85,9 +86,10 @@ describe('Search Strategy EQL helper', () => {
|
|||
pagination: { activePage: 1, querySize: 2 },
|
||||
sort: [
|
||||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.desc,
|
||||
type: 'number',
|
||||
esTypes: ['date'],
|
||||
field: '@timestamp',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
timerange: {
|
||||
|
@ -141,9 +143,10 @@ describe('Search Strategy EQL helper', () => {
|
|||
pagination: { activePage: 0, querySize: 2 },
|
||||
sort: [
|
||||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.desc,
|
||||
type: 'number',
|
||||
field: '@timestamp',
|
||||
esTypes: ['date'],
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
timerange: {
|
||||
|
@ -418,9 +421,10 @@ describe('Search Strategy EQL helper', () => {
|
|||
pagination: { activePage: 3, querySize: 2 },
|
||||
sort: [
|
||||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.desc,
|
||||
type: 'number',
|
||||
esTypes: ['date'],
|
||||
field: '@timestamp',
|
||||
type: 'date',
|
||||
},
|
||||
],
|
||||
timerange: {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 { getPreferredEsType } from './helpers';
|
||||
|
||||
describe('helpers', () => {
|
||||
describe('getPreferredEsType', () => {
|
||||
it('prefers `keyword` over other types when `esTypes` contains a `keyword` entry', () => {
|
||||
const esTypes = ['long', 'keyword'];
|
||||
|
||||
expect(getPreferredEsType(esTypes)).toEqual('keyword');
|
||||
});
|
||||
|
||||
it('returns the first entry when esTypes has multiple entries, but no `keyword` entry', () => {
|
||||
const esTypes = ['long', 'date'];
|
||||
|
||||
expect(getPreferredEsType(esTypes)).toEqual('long');
|
||||
});
|
||||
|
||||
it('returns the first entry when esTypes has only one (non-`keyword`) entry', () => {
|
||||
const esTypes = ['date'];
|
||||
|
||||
expect(getPreferredEsType(esTypes)).toEqual('date');
|
||||
});
|
||||
|
||||
it('returns `keyword` when esTypes only contains a `keyword` entry', () => {
|
||||
const esTypes: string[] = ['keyword'];
|
||||
|
||||
expect(getPreferredEsType(esTypes)).toEqual('keyword');
|
||||
});
|
||||
|
||||
it('returns `keyword` when esTypes is empty', () => {
|
||||
const esTypes: string[] = [];
|
||||
|
||||
expect(getPreferredEsType(esTypes)).toEqual('keyword');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* When `esTypes` types array contains more than one value, and one of those
|
||||
* (multiple) values is `keyword`, the `keyword` entry is returned. The
|
||||
* `keyword` entry is preferred over other values when it exists in the array.
|
||||
*
|
||||
* The `keyword` value is also returned when the `esTypes` array is empty.
|
||||
*/
|
||||
export const getPreferredEsType = (esTypes: string[]): string => {
|
||||
if (esTypes.length === 1 || (esTypes.length > 1 && !esTypes.includes('keyword'))) {
|
||||
return esTypes[0]; // no preference
|
||||
} else {
|
||||
return 'keyword'; // esTypes includes `keyword`, or it's empty
|
||||
}
|
||||
};
|
|
@ -15,6 +15,7 @@ import {
|
|||
TimelineRequestSortField,
|
||||
} from '../../../../../../common/search_strategy';
|
||||
import { createQueryFilterClauses } from '../../../../../../server/utils/build_query';
|
||||
import { getPreferredEsType } from './helpers';
|
||||
|
||||
export const buildTimelineEventsAllQuery = ({
|
||||
authFilter,
|
||||
|
@ -58,7 +59,7 @@ export const buildTimelineEventsAllQuery = ({
|
|||
return {
|
||||
[field]: {
|
||||
order: item.direction,
|
||||
unmapped_type: item.type,
|
||||
unmapped_type: getPreferredEsType(item.esTypes),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -49,7 +49,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
{
|
||||
field: '@timestamp',
|
||||
direction: Direction.desc,
|
||||
type: 'number',
|
||||
esTypes: ['date'],
|
||||
},
|
||||
],
|
||||
timerange: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue