diff --git a/.backportrc.json b/.backportrc.json index 2603eb2e2d444..731f49183dba5 100644 --- a/.backportrc.json +++ b/.backportrc.json @@ -1,5 +1,30 @@ { "upstream": "elastic/kibana", - "branches": [{ "name": "7.x", "checked": true }, "7.7", "7.6", "7.5", "7.4", "7.3", "7.2", "7.1", "7.0", "6.8", "6.7", "6.6", "6.5", "6.4", "6.3", "6.2", "6.1", "6.0", "5.6"], - "labels": ["backport"] + "targetBranchChoices": [ + { "name": "master", "checked": true }, + { "name": "7.x", "checked": true }, + "7.7", + "7.6", + "7.5", + "7.4", + "7.3", + "7.2", + "7.1", + "7.0", + "6.8", + "6.7", + "6.6", + "6.5", + "6.4", + "6.3", + "6.2", + "6.1", + "6.0", + "5.6" + ], + "targetPRLabels": ["backport"], + "branchLabelMapping": { + "^v7.8.0$": "7.x", + "^v(\\d+).(\\d+).\\d+$": "$1.$2" + } } diff --git a/.ci/es-snapshots/Jenkinsfile_verify_es b/.ci/es-snapshots/Jenkinsfile_verify_es index ade79f27e10e9..2655ca1b48c18 100644 --- a/.ci/es-snapshots/Jenkinsfile_verify_es +++ b/.ci/es-snapshots/Jenkinsfile_verify_es @@ -21,6 +21,7 @@ def SNAPSHOT_MANIFEST = "https://storage.googleapis.com/kibana-ci-es-snapshots-d kibanaPipeline(timeoutMinutes: 120) { catchErrors { + retryable.enable(2) withEnv(["ES_SNAPSHOT_MANIFEST=${SNAPSHOT_MANIFEST}"]) { parallel([ 'kibana-intake-agent': workers.intake('kibana-intake', './test/scripts/jenkins_unit.sh'), diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3981a8e1e9afe..6e616cf78c206 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,26 +3,28 @@ # For more info, see https://help.github.com/articles/about-codeowners/ # App +/x-pack/plugins/dashboard_enhanced/ @elastic/kibana-app /x-pack/plugins/lens/ @elastic/kibana-app /x-pack/plugins/graph/ @elastic/kibana-app /src/legacy/server/url_shortening/ @elastic/kibana-app /src/legacy/server/sample_data/ @elastic/kibana-app -/src/legacy/core_plugins/kibana/public/dashboard/ @elastic/kibana-app -/src/legacy/core_plugins/kibana/public/discover/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/local_application_service/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/dev_tools/ @elastic/kibana-app -/src/plugins/vis_type_vislib/ @elastic/kibana-app -/src/plugins/vis_type_xy/ @elastic/kibana-app -/src/plugins/vis_type_table/ @elastic/kibana-app -/src/plugins/kibana_legacy/ @elastic/kibana-app -/src/plugins/vis_type_timelion/ @elastic/kibana-app /src/plugins/dashboard/ @elastic/kibana-app /src/plugins/discover/ @elastic/kibana-app /src/plugins/input_control_vis/ @elastic/kibana-app -/src/plugins/visualize/ @elastic/kibana-app -/src/plugins/vis_type_timeseries/ @elastic/kibana-app -/src/plugins/vis_type_metric/ @elastic/kibana-app +/src/plugins/kibana_legacy/ @elastic/kibana-app +/src/plugins/vis_default_editor/ @elastic/kibana-app /src/plugins/vis_type_markdown/ @elastic/kibana-app +/src/plugins/vis_type_metric/ @elastic/kibana-app +/src/plugins/vis_type_table/ @elastic/kibana-app +/src/plugins/vis_type_tagcloud/ @elastic/kibana-app +/src/plugins/vis_type_timelion/ @elastic/kibana-app +/src/plugins/vis_type_timeseries/ @elastic/kibana-app +/src/plugins/vis_type_vega/ @elastic/kibana-app +/src/plugins/vis_type_vislib/ @elastic/kibana-app +/src/plugins/vis_type_xy/ @elastic/kibana-app +/src/plugins/visualize/ @elastic/kibana-app # Core UI # Exclude tutorials folder for now because they are not owned by Kibana app and most will move out soon diff --git a/.i18nrc.json b/.i18nrc.json index b04c02f6b2265..be3c043b6e52f 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -8,6 +8,7 @@ "data": "src/plugins/data", "embeddableApi": "src/plugins/embeddable", "embeddableExamples": "examples/embeddable_examples", + "uiActionsExamples": "examples/ui_action_examples", "share": "src/plugins/share", "home": "src/plugins/home", "charts": "src/plugins/charts", diff --git a/docs/canvas/canvas-function-reference.asciidoc b/docs/canvas/canvas-function-reference.asciidoc index 16aaf55802b17..657e3ec8b8bb1 100644 --- a/docs/canvas/canvas-function-reference.asciidoc +++ b/docs/canvas/canvas-function-reference.asciidoc @@ -42,10 +42,10 @@ filters | metric "Average uptime" metricFont={ font size=48 family="'Open Sans', Helvetica, Arial, sans-serif" - color={ - if {all {gte 0} {lt 0.8}} then="red" else="green" - } - align="center" lHeight=48 + color={ + if {all {gte 0} {lt 0.8}} then="red" else="green" + } + align="center" lHeight=48 } | render ---- @@ -324,12 +324,14 @@ case if={lte 50} then="green" ---- math "random()" | progress shape="gauge" label={formatnumber "0%"} - font={font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" align="center" - color={ - switch {case if={lte 0.5} then="green"} - {case if={all {gt 0.5} {lte 0.75}} then="orange"} - default="red" - }} + font={ + font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" align="center" + color={ + switch {case if={lte 0.5} then="green"} + {case if={all {gt 0.5} {lte 0.75}} then="orange"} + default="red" + } + } valueColor={ switch {case if={lte 0.5} then="green"} {case if={all {gt 0.5} {lte 0.75}} then="orange"} @@ -693,7 +695,25 @@ Alias: `value` [[demodata_fn]] === `demodata` -A mock data set that includes project CI times with usernames, countries, and run phases. +A sample data set that includes project CI times with usernames, countries, and run phases. + +*Expression syntax* +[source,js] +---- +demodata +demodata "ci" +demodata type="shirts" +---- + +*Code example* +[source,text] +---- +filters +| demodata +| table +| render +---- +`demodata` is a mock data set that you can use to start playing around in Canvas. *Accepts:* `filter` @@ -837,6 +857,28 @@ Alias: `value` Query Elasticsearch for the number of hits matching the specified query. +*Expression syntax* +[source,js] +---- +escount index="logstash-*" +escount "currency:"EUR"" index="kibana_sample_data_ecommerce" +escount query="response:404" index="kibana_sample_data_logs" +---- + +*Code example* +[source,text] +---- +filters +| escount "Cancelled:true" index="kibana_sample_data_flights" +| math "value" +| progress shape="semicircle" + label={formatnumber 0,0} + font={font size=24 family="'Open Sans', Helvetica, Arial, sans-serif" color="#000000" align=center} + max={filters | escount index="kibana_sample_data_flights"} +| render +---- +The first `escount` expression retrieves the number of flights that were cancelled. The second `escount` expression retrieves the total number of flights. + *Accepts:* `filter` [cols="3*^<"] @@ -867,6 +909,34 @@ Default: `_all` Query Elasticsearch for raw documents. Specify the fields you want to retrieve, especially if you are asking for a lot of rows. +*Expression syntax* +[source,js] +---- +esdocs index="logstash-*" +esdocs "currency:"EUR"" index="kibana_sample_data_ecommerce" +esdocs query="response:404" index="kibana_sample_data_logs" +esdocs index="kibana_sample_data_flights" count=100 +esdocs index="kibana_sample_data_flights" sort="AvgTicketPrice, asc" +---- + +*Code example* +[source,text] +---- +filters +| esdocs index="kibana_sample_data_ecommerce" + fields="customer_gender, taxful_total_price, order_date" + sort="order_date, asc" + count=10000 +| mapColumn "order_date" + fn={getCell "order_date" | date {context} | rounddate "YYYY-MM-DD"} +| alterColumn "order_date" type="date" +| pointseries x="order_date" y="sum(taxful_total_price)" color="customer_gender" +| plot defaultStyle={seriesStyle lines=3} + palette={palette "#7ECAE3" "#003A4D" gradient=true} +| render +---- +This retrieves the first 10000 documents data from the `kibana_sample_data_ecommerce` index sorted by `order_date` in ascending order, and only requests the `customer_gender`, `taxful_total_price`, and `order_date` fields. + *Accepts:* `filter` [cols="3*^<"] @@ -915,6 +985,23 @@ Default: `_all` Queries Elasticsearch using Elasticsearch SQL. +*Expression syntax* +[source,js] +---- +essql query="SELECT * FROM "logstash*"" +essql "SELECT * FROM "apm*"" count=10000 +---- + +*Code example* +[source,text] +---- +filters +| essql query="SELECT Carrier, FlightDelayMin, AvgTicketPrice FROM "kibana_sample_data_flights"" +| table +| render +---- +This retrieves the `Carrier`, `FlightDelayMin`, and `AvgTicketPrice` fields from the "kibana_sample_data_flights" index. + *Accepts:* `filter` [cols="3*^<"] @@ -1107,7 +1194,7 @@ Default: `false` [[font_fn]] === `font` -Creates a font style. +Create a font style. *Expression syntax* [source,js] @@ -1244,7 +1331,7 @@ Alias: `format` [[formatnumber_fn]] === `formatnumber` -Formats a number into a formatted number string using the <>. +Formats a number into a formatted number string using the Numeral pattern. *Expression syntax* [source,js] @@ -1276,7 +1363,7 @@ The `formatnumber` subexpression receives the same `context` as the `progress` f Alias: `format` |`string` -|A <> string. For example, `"0.0a"` or `"0%"`. +|A Numeral pattern format string. For example, `"0.0a"` or `"0%"`. |=== *Returns:* `string` @@ -1559,6 +1646,34 @@ Alias: `value` [[m_fns]] == M +[float] +[[mapCenter_fn]] +=== `mapCenter` + +Returns an object with the center coordinates and zoom level of the map. + +*Accepts:* `null` + +[cols="3*^<"] +|=== +|Argument |Type |Description + +|`lat` *** +|`number` +|Latitude for the center of the map + +|`lon` *** +|`number` +|Longitude for the center of the map + +|`zoom` *** +|`number` +|Zoom level of the map +|=== + +*Returns:* `mapCenter` + + [float] [[mapColumn_fn]] === `mapColumn` @@ -1612,6 +1727,12 @@ Default: `""` |The CSS font properties for the content. For example, "font-family" or "font-weight". Default: `${font}` + +|`openLinksInNewTab` +|`boolean` +|A true or false value for opening links in a new tab. The default value is `false`. Setting to `true` opens all links in a new tab. + +Default: `false` |=== *Returns:* `render` @@ -1675,7 +1796,7 @@ Default: `${font size=48 family="'Open Sans', Helvetica, Arial, sans-serif" colo Alias: `format` |`string` -|A <> string. For example, `"0.0a"` or `"0%"`. +|A Numeral pattern format string. For example, `"0.0a"` or `"0%"`. |=== *Returns:* `render` @@ -2184,6 +2305,102 @@ Returns the number of rows. Pairs with <> to get the count of unique col [[s_fns]] == S +[float] +[[savedLens_fn]] +=== `savedLens` + +Returns an embeddable for a saved Lens visualization object. + +*Accepts:* `any` + +[cols="3*^<"] +|=== +|Argument |Type |Description + +|`id` +|`string` +|The ID of the saved Lens visualization object + +|`timerange` +|`timerange` +|The timerange of data that should be included + +|`title` +|`string` +|The title for the Lens visualization object +|=== + +*Returns:* `embeddable` + + +[float] +[[savedMap_fn]] +=== `savedMap` + +Returns an embeddable for a saved map object. + +*Accepts:* `any` + +[cols="3*^<"] +|=== +|Argument |Type |Description + +|`center` +|`mapCenter` +|The center and zoom level the map should have + +|`hideLayer` † +|`string` +|The IDs of map layers that should be hidden + +|`id` +|`string` +|The ID of the saved map object + +|`timerange` +|`timerange` +|The timerange of data that should be included + +|`title` +|`string` +|The title for the map +|=== + +*Returns:* `embeddable` + + +[float] +[[savedVisualization_fn]] +=== `savedVisualization` + +Returns an embeddable for a saved visualization object. + +*Accepts:* `any` + +[cols="3*^<"] +|=== +|Argument |Type |Description + +|`colors` † +|`seriesStyle` +|Defines the color to use for a specific series + +|`hideLegend` +|`boolean` +|Specifies the option to hide the legend + +|`id` +|`string` +|The ID of the saved visualization object + +|`timerange` +|`timerange` +|The timerange of data that should be included +|=== + +*Returns:* `embeddable` + + [float] [[seriesStyle_fn]] === `seriesStyle` @@ -2579,6 +2796,30 @@ Default: `"now"` *Returns:* `datatable` +[float] +[[timerange_fn]] +=== `timerange` + +An object that represents a span of time. + +*Accepts:* `null` + +[cols="3*^<"] +|=== +|Argument |Type |Description + +|`from` *** +|`string` +|The start of the time range + +|`to` *** +|`string` +|The end of the time range +|=== + +*Returns:* `timerange` + + [float] [[to_fn]] === `to` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md index 7fd65e5db35f3..37142cf1794c3 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.esfilters.md @@ -49,6 +49,7 @@ esFilters: { generateFilters: typeof generateFilters; onlyDisabledFiltersChanged: (newFilters?: import("../common").Filter[] | undefined, oldFilters?: import("../common").Filter[] | undefined) => boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; } diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md index c3b2ac8d30b5a..faa793d4e9dfd 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field._constructor_.md @@ -9,7 +9,7 @@ Constructs a new instance of the `Field` class Signature: ```typescript -constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable?: boolean); +constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable: boolean, { fieldFormats, toastNotifications }: FieldDependencies); ``` ## Parameters @@ -19,4 +19,5 @@ constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable | indexPattern | IndexPattern | | | spec | FieldSpec | Field | | | shortDotsEnable | boolean | | +| { fieldFormats, toastNotifications } | FieldDependencies | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md index 86ff2b2c28ae9..692f34e0d81df 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.field.md @@ -14,7 +14,7 @@ export declare class Field implements IFieldType | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(indexPattern, spec, shortDotsEnable)](./kibana-plugin-plugins-data-public.field._constructor_.md) | | Constructs a new instance of the Field class | +| [(constructor)(indexPattern, spec, shortDotsEnable, { fieldFormats, toastNotifications })](./kibana-plugin-plugins-data-public.field._constructor_.md) | | Constructs a new instance of the Field class | ## Properties diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md new file mode 100644 index 0000000000000..60302286cbd72 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [getIndexPatternFieldListCreator](./kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md) + +## getIndexPatternFieldListCreator variable + +Signature: + +```typescript +getIndexPatternFieldListCreator: ({ fieldFormats, toastNotifications, }: FieldListDependencies) => CreateIndexPatternFieldList +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.add.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.add.md new file mode 100644 index 0000000000000..0f3469ae9c550 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.add.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) > [add](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.add.md) + +## IIndexPatternFieldList.add() method + +Signature: + +```typescript +add(field: FieldSpec): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| field | FieldSpec | | + +Returns: + +`void` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbyname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbyname.md new file mode 100644 index 0000000000000..14b5aa7137dc2 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbyname.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) > [getByName](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbyname.md) + +## IIndexPatternFieldList.getByName() method + +Signature: + +```typescript +getByName(name: Field['name']): Field | undefined; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| name | Field['name'] | | + +Returns: + +`Field | undefined` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbytype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbytype.md new file mode 100644 index 0000000000000..3c65b78e5291d --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbytype.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) > [getByType](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbytype.md) + +## IIndexPatternFieldList.getByType() method + +Signature: + +```typescript +getByType(type: Field['type']): Field[]; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| type | Field['type'] | | + +Returns: + +`Field[]` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.md new file mode 100644 index 0000000000000..47d7c7491aa86 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) + +## IIndexPatternFieldList interface + +Signature: + +```typescript +export interface IIndexPatternFieldList extends Array +``` + +## Methods + +| Method | Description | +| --- | --- | +| [add(field)](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.add.md) | | +| [getByName(name)](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbyname.md) | | +| [getByType(type)](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.getbytype.md) | | +| [remove(field)](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.remove.md) | | +| [update(field)](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.update.md) | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.remove.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.remove.md new file mode 100644 index 0000000000000..3b6bbb0691930 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.remove.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) > [remove](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.remove.md) + +## IIndexPatternFieldList.remove() method + +Signature: + +```typescript +remove(field: IFieldType): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| field | IFieldType | | + +Returns: + +`void` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.update.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.update.md new file mode 100644 index 0000000000000..121ffb65f26a5 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.iindexpatternfieldlist.update.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) > [update](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.update.md) + +## IIndexPatternFieldList.update() method + +Signature: + +```typescript +update(field: FieldSpec): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| field | FieldSpec | | + +Returns: + +`void` + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md index fcd682340eb53..9a93148e4a466 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md @@ -7,5 +7,5 @@ Signature: ```typescript -fields: IFieldList; +fields: IIndexPatternFieldList; ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md index 35075e19dcaf6..21a155ba977c9 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md @@ -21,7 +21,7 @@ export declare class IndexPattern implements IIndexPattern | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [fieldFormatMap](./kibana-plugin-plugins-data-public.indexpattern.fieldformatmap.md) | | any | | -| [fields](./kibana-plugin-plugins-data-public.indexpattern.fields.md) | | IFieldList | | +| [fields](./kibana-plugin-plugins-data-public.indexpattern.fields.md) | | IIndexPatternFieldList | | | [fieldsFetcher](./kibana-plugin-plugins-data-public.indexpattern.fieldsfetcher.md) | | any | | | [flattenHit](./kibana-plugin-plugins-data-public.indexpattern.flattenhit.md) | | any | | | [formatField](./kibana-plugin-plugins-data-public.indexpattern.formatfield.md) | | any | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist._constructor_.md deleted file mode 100644 index 2207107db8b2b..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist._constructor_.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [(constructor)](./kibana-plugin-plugins-data-public.indexpatternfieldlist._constructor_.md) - -## IndexPatternFieldList.(constructor) - -Constructs a new instance of the `FieldList` class - -Signature: - -```typescript -constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean); -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| indexPattern | IndexPattern | | -| specs | FieldSpec[] | | -| shortDotsEnable | boolean | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.add.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.add.md deleted file mode 100644 index dce2f38bbcf10..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.add.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [add](./kibana-plugin-plugins-data-public.indexpatternfieldlist.add.md) - -## IndexPatternFieldList.add property - -Signature: - -```typescript -add: (field: Record) => void; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md deleted file mode 100644 index bf6bc51b60301..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [getByName](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md) - -## IndexPatternFieldList.getByName property - -Signature: - -```typescript -getByName: (name: string) => Field | undefined; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md deleted file mode 100644 index 86c5ae32940d4..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [getByType](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md) - -## IndexPatternFieldList.getByType property - -Signature: - -```typescript -getByType: (type: string) => any[]; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md deleted file mode 100644 index 478b73f5f8581..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.md +++ /dev/null @@ -1,28 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) - -## IndexPatternFieldList class - -Signature: - -```typescript -export declare class FieldList extends Array implements IFieldList -``` - -## Constructors - -| Constructor | Modifiers | Description | -| --- | --- | --- | -| [(constructor)(indexPattern, specs, shortDotsEnable)](./kibana-plugin-plugins-data-public.indexpatternfieldlist._constructor_.md) | | Constructs a new instance of the FieldList class | - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [add](./kibana-plugin-plugins-data-public.indexpatternfieldlist.add.md) | | (field: Record<string, any>) => void | | -| [getByName](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbyname.md) | | (name: string) => Field | undefined | | -| [getByType](./kibana-plugin-plugins-data-public.indexpatternfieldlist.getbytype.md) | | (type: string) => any[] | | -| [remove](./kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md) | | (field: IFieldType) => void | | -| [update](./kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md) | | (field: Record<string, any>) => void | | - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md deleted file mode 100644 index 1f2e0883d272e..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [remove](./kibana-plugin-plugins-data-public.indexpatternfieldlist.remove.md) - -## IndexPatternFieldList.remove property - -Signature: - -```typescript -remove: (field: IFieldType) => void; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md deleted file mode 100644 index d5156ed41e493..0000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) > [update](./kibana-plugin-plugins-data-public.indexpatternfieldlist.update.md) - -## IndexPatternFieldList.update property - -Signature: - -```typescript -update: (field: Record) => void; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 13e38ba5e6e5d..f1024c0954251 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -13,7 +13,6 @@ | [FieldFormat](./kibana-plugin-plugins-data-public.fieldformat.md) | | | [FilterManager](./kibana-plugin-plugins-data-public.filtermanager.md) | | | [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) | | -| [IndexPatternFieldList](./kibana-plugin-plugins-data-public.indexpatternfieldlist.md) | | | [IndexPatternSelect](./kibana-plugin-plugins-data-public.indexpatternselect.md) | | | [OptionedParamType](./kibana-plugin-plugins-data-public.optionedparamtype.md) | | | [Plugin](./kibana-plugin-plugins-data-public.plugin.md) | | @@ -61,6 +60,7 @@ | [IFieldSubType](./kibana-plugin-plugins-data-public.ifieldsubtype.md) | | | [IFieldType](./kibana-plugin-plugins-data-public.ifieldtype.md) | | | [IIndexPattern](./kibana-plugin-plugins-data-public.iindexpattern.md) | | +| [IIndexPatternFieldList](./kibana-plugin-plugins-data-public.iindexpatternfieldlist.md) | | | [IKibanaSearchRequest](./kibana-plugin-plugins-data-public.ikibanasearchrequest.md) | | | [IKibanaSearchResponse](./kibana-plugin-plugins-data-public.ikibanasearchresponse.md) | | | [IndexPatternAttributes](./kibana-plugin-plugins-data-public.indexpatternattributes.md) | Use data plugin interface instead | @@ -103,6 +103,7 @@ | [esQuery](./kibana-plugin-plugins-data-public.esquery.md) | | | [fieldFormats](./kibana-plugin-plugins-data-public.fieldformats.md) | | | [FilterBar](./kibana-plugin-plugins-data-public.filterbar.md) | | +| [getIndexPatternFieldListCreator](./kibana-plugin-plugins-data-public.getindexpatternfieldlistcreator.md) | | | [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {Array} | | [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | | | [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md index d0d4cc491e142..58690300b3bd6 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md @@ -7,5 +7,5 @@ Signature: ```typescript -QueryStringInput: React.FC> +QueryStringInput: React.FC> ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index a0b879673e553..0d5e0e42af27f 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "customSubmitButton" | "screenTitle" | "dataTestSubj" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/docs/discover/images/autorefresh-interval.png b/docs/discover/images/autorefresh-interval.png new file mode 100644 index 0000000000000..a9f72a1cb73cd Binary files /dev/null and b/docs/discover/images/autorefresh-interval.png differ diff --git a/docs/discover/search.asciidoc b/docs/discover/search.asciidoc index 21ae4560fba94..9fe35f0302760 100644 --- a/docs/discover/search.asciidoc +++ b/docs/discover/search.asciidoc @@ -1,25 +1,53 @@ [[search]] == Searching your data -You can search the indices that match the current <> by entering -your search criteria in the Query bar. By default you can use Kibana's <> -which features autocomplete and a simple, easy to use syntax. Kibana's legacy query -language (based on Lucene https://lucene.apache.org/core/2_9_4/queryparsersyntax.html[query syntax]) -is still available for the time being under the options menu in the Query Bar. When this -legacy query language is selected, the full JSON-based {ref}/query-dsl.html[Elasticsearch Query DSL] -can also be used. - -When you submit a search request, the histogram, Documents table, and Fields -list are updated to reflect the search results. The total number of hits -(matching documents) is shown in the toolbar. The Documents table shows the -first five hundred hits. By default, the hits are listed in reverse -chronological order, with the newest documents shown first. You can reverse -the sort order by clicking the Time column header. You can also sort the table -by the values in any indexed field. For more information, see <>. - -To search your data, enter your search criteria in the Query bar and -press *Enter* or click *Search* image:images/search-button.jpg[] to submit -the request to Elasticsearch. +Many Kibana apps embed a query bar for real-time search, including +*Discover*, *Visualize*, and *Dashboard*. + +[float] +=== Search your data + +To search the indices that match the current <>, +enter your search criteria in the query bar. By default, you'll use +{kib}'s <> (KQL), which +features autocomplete and a simple, easy-to-use syntax. If you prefer to use +{kib}'s legacy query +language, based on the +Lucene https://lucene.apache.org/core/2_9_4/queryparsersyntax.html[query syntax], +you can switch to it from the KQL popup in the query bar. When you enable the +legacy query language, you can use the full +JSON-based {ref}/query-dsl.html[Elasticsearch Query DSL]. + + +[float] +[[autorefresh]] +=== Refresh search results +As more documents are added to the indices you're searching, the search results +shown in *Discover*, and used to display visualizations, get stale. Using the +time filter, you can +configure a refresh interval to periodically resubmit your searches to +retrieve the latest results. + +[role="screenshot"] +image::images/autorefresh-interval.png[] + +You can also manually refresh the search results by +clicking the *Refresh* button. + +[float] +=== Searching large amounts of data + +Sometimes you want to search through large amounts of data no matter how long +the search takes. While this might not happen often, there are times +that long-running queries are required. Consider a threat hunting scenario +where you need to search through years of data. + +If you run a query, and the run time gets close to the +timeout, you're presented the option to ignore the timeout. This enables you to +run queries with large amounts of data to completion. + +By default, a query times out after 30 seconds. +The timeout is in place to avoid unintentional load on the cluster. + include::kuery.asciidoc[] @@ -160,31 +188,3 @@ To completely delete a query: image::discover/images/saved-query-management-component-delete-query-button.png["Example of the saved query management popover when a query is hovered over and we are about to delete a query",width="80%"] You can import, export, and delete saved queries from <>. - -[[select-pattern]] -=== Change the indices you're searching -When you submit a search request, the indices that match the currently-selected -index pattern are searched. -To change the indices you are searching, click the index pattern and select a -different <>. - -[[autorefresh]] -=== Refresh the search results -As more documents are added to the indices you're searching, the search results -shown in Discover and used to display visualizations get stale. You can -configure a refresh interval to periodically resubmit your searches to -retrieve the latest results. - -. Click image:images/time-filter-calendar.png[]. - -. In the *Refresh every* field, enter the refresh rate, then select the interval - from the dropdown. - -. Click *Start*. -+ -image::images/autorefresh-intervals.png[] - -To disable auto refresh, click *Stop*. - -If auto refresh is not enabled, click *Refresh* to manually refresh the search -results. diff --git a/docs/images/autorefresh-intervals.png b/docs/images/autorefresh-intervals.png index a79ae2f1f6c46..49be46fefd4aa 100644 Binary files a/docs/images/autorefresh-intervals.png and b/docs/images/autorefresh-intervals.png differ diff --git a/docs/logs/images/alert-actions-menu.png b/docs/logs/images/alert-actions-menu.png new file mode 100644 index 0000000000000..3f96a700a0ac1 Binary files /dev/null and b/docs/logs/images/alert-actions-menu.png differ diff --git a/docs/logs/images/alert-flyout.png b/docs/logs/images/alert-flyout.png new file mode 100644 index 0000000000000..30c8857758a8b Binary files /dev/null and b/docs/logs/images/alert-flyout.png differ diff --git a/docs/logs/index.asciidoc b/docs/logs/index.asciidoc index b12dc096bff45..0d225e5e89c17 100644 --- a/docs/logs/index.asciidoc +++ b/docs/logs/index.asciidoc @@ -17,6 +17,7 @@ In this case, you will only see the logs for the selected component. * <> * <> * <> +* <> [role="screenshot"] image::logs/images/logs-console.png[Log Console in Kibana] @@ -30,3 +31,5 @@ include::using.asciidoc[] include::configuring.asciidoc[] include::log-rate.asciidoc[] + +include::logs-alerting.asciidoc[] diff --git a/docs/logs/logs-alerting.asciidoc b/docs/logs/logs-alerting.asciidoc new file mode 100644 index 0000000000000..f08a09187a0c8 --- /dev/null +++ b/docs/logs/logs-alerting.asciidoc @@ -0,0 +1,27 @@ +[role="xpack"] +[[xpack-logs-alerting]] +== Logs alerting + +[float] +=== Overview + +To use the alerting functionality you need to {kibana-ref}/alerting-getting-started.html#alerting-setup-prerequisites[set up alerting]. + +You can then select the *Create alert* option, from the *Alerts* actions dropdown. + +[role="screenshot"] +image::logs/images/alert-actions-menu.png[Screenshot showing alerts menu] + +Within the alert flyout you can configure your logs alert: + +[role="screenshot"] +image::logs/images/alert-flyout.png[Screenshot showing alerts flyout] + +[float] +=== Fields and comparators + +The comparators available for conditions depend on the chosen field. The combinations available are: + +- Numeric fields: *more than*, *more than or equals*, *less than*, *less than or equals*, *equals*, and *does not equal*. +- Aggregatable fields: *is* and *is not*. +- Non-aggregatable fields: *matches*, *does not match*, *matches phrase*, *does not match phrase*. diff --git a/docs/redirects.asciidoc b/docs/redirects.asciidoc index a5503969a3ec1..85d580de9475f 100644 --- a/docs/redirects.asciidoc +++ b/docs/redirects.asciidoc @@ -70,3 +70,13 @@ This page has moved. Please see <>. == Maps This page has moved. Please see <>. + +[role="exclude",id="development-embedding-visualizations"] +== Embedding Visualizations + +This page was deleted. See <>. + +[role="exclude",id="development-create-visualization"] +== Developing Visualizations + +This page was deleted. See <>. diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index d4dbe9407b7a9..547b4fdedcec6 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -5,7 +5,7 @@ Alerting and action settings ++++ -Alerts and actions are enabled by default in {kib}, but require you configure the following in order to use them: +Alerts and actions are enabled by default in {kib}, but require you configure the following in order to use them: . <>. . <>. @@ -18,27 +18,36 @@ You can configure the following settings in the `kibana.yml` file. [[general-alert-action-settings]] ==== General settings -`xpack.encryptedSavedObjects.encryptionKey`:: +[cols="2*<"] +|=== -A string of 32 or more characters used to encrypt sensitive properties on alerts and actions before they're stored in {es}. Third party credentials — such as the username and password used to connect to an SMTP service — are an example of encrypted properties. -+ -If not set, {kib} will generate a random key on startup, but all alert and action functions will be blocked. Generated keys are not allowed for alerts and actions because when a new key is generated on restart, existing encrypted data becomes inaccessible. For the same reason, alerts and actions in high-availability deployments of {kib} will behave unexpectedly if the key isn't the same on all instances of {kib}. -+ -Although the key can be specified in clear text in `kibana.yml`, it's recommended to store this key securely in the <>. +| `xpack.encryptedSavedObjects.encryptionKey` + | A string of 32 or more characters used to encrypt sensitive properties on alerts and actions before they're stored in {es}. Third party credentials — such as the username and password used to connect to an SMTP service — are an example of encrypted properties. + + + + If not set, {kib} will generate a random key on startup, but all alert and action functions will be blocked. Generated keys are not allowed for alerts and actions because when a new key is generated on restart, existing encrypted data becomes inaccessible. For the same reason, alerts and actions in high-availability deployments of {kib} will behave unexpectedly if the key isn't the same on all instances of {kib}. + + + + Although the key can be specified in clear text in `kibana.yml`, it's recommended to store this key securely in the <>. + +|=== [float] [[action-settings]] ==== Action settings -`xpack.actions.whitelistedHosts`:: -A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly whitelisted. An empty list `[]` can be used to block built-in actions from making any external connections. -+ -Note that hosts associated with built-in actions, such as Slack and PagerDuty, are not automatically whitelisted. If you are not using the default `[*]` setting, you must ensure that the corresponding endpoints are whitelisted as well. +[cols="2*<"] +|=== + +| `xpack.actions.whitelistedHosts` + | A list of hostnames that {kib} is allowed to connect to when built-in actions are triggered. It defaults to `[*]`, allowing any host, but keep in mind the potential for SSRF attacks when hosts are not explicitly whitelisted. An empty list `[]` can be used to block built-in actions from making any external connections. + + + + Note that hosts associated with built-in actions, such as Slack and PagerDuty, are not automatically whitelisted. If you are not using the default `[*]` setting, you must ensure that the corresponding endpoints are whitelisted as well. + +| `xpack.actions.enabledActionTypes` + | A list of action types that are enabled. It defaults to `[*]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, and `.webhook`. An empty list `[]` will disable all action types. + + + + Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. -`xpack.actions.enabledActionTypes`:: -A list of action types that are enabled. It defaults to `[*]`, enabling all types. The names for built-in {kib} action types are prefixed with a `.` and include: `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, and `.webhook`. An empty list `[]` will disable all action types. -+ -Disabled action types will not appear as an option when creating new connectors, but existing connectors and actions of that type will remain in {kib} and will not function. +|=== [float] [[alert-settings]] diff --git a/docs/settings/apm-settings.asciidoc b/docs/settings/apm-settings.asciidoc index fd53c3aeb3605..8844fcd03ae9a 100644 --- a/docs/settings/apm-settings.asciidoc +++ b/docs/settings/apm-settings.asciidoc @@ -38,27 +38,42 @@ If you'd like to change any of the default values, copy and paste the relevant settings into your `kibana.yml` configuration file. Changing these settings may disable features of the APM App. -xpack.apm.enabled:: Set to `false` to disable the APM app. Defaults to `true`. +[cols="2*<"] +|=== +| `xpack.apm.enabled` + | Set to `false` to disable the APM app. Defaults to `true`. -xpack.apm.ui.enabled:: Set to `false` to hide the APM app from the menu. Defaults to `true`. +| `xpack.apm.ui.enabled` + | Set to `false` to hide the APM app from the menu. Defaults to `true`. -xpack.apm.ui.transactionGroupBucketSize:: Number of top transaction groups displayed in the APM app. Defaults to `100`. +| `xpack.apm.ui.transactionGroupBucketSize` + | Number of top transaction groups displayed in the APM app. Defaults to `100`. -xpack.apm.ui.maxTraceItems:: Maximum number of child items displayed when viewing trace details. Defaults to `1000`. +| `xpack.apm.ui.maxTraceItems` + | Maximum number of child items displayed when viewing trace details. Defaults to `1000`. -apm_oss.indexPattern:: The index pattern used for integrations with Machine Learning and Query Bar. -It must match all apm indices. Defaults to `apm-*`. +| `apm_oss.indexPattern` + | The index pattern used for integrations with Machine Learning and Query Bar. + It must match all apm indices. Defaults to `apm-*`. -apm_oss.errorIndices:: Matcher for all {apm-server-ref}/error-indices.html[error indices]. Defaults to `apm-*`. +| `apm_oss.errorIndices` + | Matcher for all {apm-server-ref}/error-indices.html[error indices]. Defaults to `apm-*`. -apm_oss.onboardingIndices:: Matcher for all onboarding indices. Defaults to `apm-*`. +| `apm_oss.onboardingIndices` + | Matcher for all onboarding indices. Defaults to `apm-*`. -apm_oss.spanIndices:: Matcher for all {apm-server-ref}/span-indices.html[span indices]. Defaults to `apm-*`. +| `apm_oss.spanIndices` + | Matcher for all {apm-server-ref}/span-indices.html[span indices]. Defaults to `apm-*`. -apm_oss.transactionIndices:: Matcher for all {apm-server-ref}/transaction-indices.html[transaction indices]. Defaults to `apm-*`. +| `apm_oss.transactionIndices` + | Matcher for all {apm-server-ref}/transaction-indices.html[transaction indices]. Defaults to `apm-*`. -apm_oss.metricsIndices:: Matcher for all {apm-server-ref}/metricset-indices.html[metrics indices]. Defaults to `apm-*`. +| `apm_oss.metricsIndices` + | Matcher for all {apm-server-ref}/metricset-indices.html[metrics indices]. Defaults to `apm-*`. -apm_oss.sourcemapIndices:: Matcher for all {apm-server-ref}/sourcemap-indices.html[source map indices]. Defaults to `apm-*`. +| `apm_oss.sourcemapIndices` + | Matcher for all {apm-server-ref}/sourcemap-indices.html[source map indices]. Defaults to `apm-*`. + +|=== // end::general-apm-settings[] diff --git a/docs/settings/dev-settings.asciidoc b/docs/settings/dev-settings.asciidoc index 436f169b82ca3..c43b96a8668e0 100644 --- a/docs/settings/dev-settings.asciidoc +++ b/docs/settings/dev-settings.asciidoc @@ -12,12 +12,20 @@ They are enabled by default. [[grok-settings]] ==== Grok Debugger settings -`xpack.grokdebugger.enabled`:: -Set to `true` (default) to enable the <>. +[cols="2*<"] +|=== +| `xpack.grokdebugger.enabled` + | Set to `true` to enable the <>. Defaults to `true`. + +|=== [float] [[profiler-settings]] ==== {searchprofiler} Settings -`xpack.searchprofiler.enabled`:: -Set to `true` (default) to enable the <>. +[cols="2*<"] +|=== +| `xpack.searchprofiler.enabled` + | Set to `true` to enable the <>. Defaults to `true`. + +|=== diff --git a/docs/settings/general-infra-logs-ui-settings.asciidoc b/docs/settings/general-infra-logs-ui-settings.asciidoc index 7b32372a1f59a..2a9d4df1ff43c 100644 --- a/docs/settings/general-infra-logs-ui-settings.asciidoc +++ b/docs/settings/general-infra-logs-ui-settings.asciidoc @@ -1,17 +1,30 @@ -`xpack.infra.enabled`:: Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. +[cols="2*<"] +|=== +| `xpack.infra.enabled` + | Set to `false` to disable the Logs and Metrics app plugin {kib}. Defaults to `true`. -`xpack.infra.sources.default.logAlias`:: Index pattern for matching indices that contain log data. Defaults to `filebeat-*,kibana_sample_data_logs*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. +| `xpack.infra.sources.default.logAlias` + | Index pattern for matching indices that contain log data. Defaults to `filebeat-*,kibana_sample_data_logs*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. -`xpack.infra.sources.default.metricAlias`:: Index pattern for matching indices that contain Metricbeat data. Defaults to `metricbeat-*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. +| `xpack.infra.sources.default.metricAlias` + | Index pattern for matching indices that contain Metricbeat data. Defaults to `metricbeat-*`. To match multiple wildcard patterns, use a comma to separate the names, with no space after the comma. For example, `logstash-app1-*,default-logs-*`. -`xpack.infra.sources.default.fields.timestamp`:: Timestamp used to sort log entries. Defaults to `@timestamp`. +| `xpack.infra.sources.default.fields.timestamp` + | Timestamp used to sort log entries. Defaults to `@timestamp`. -`xpack.infra.sources.default.fields.message`:: Fields used to display messages in the Logs app. Defaults to `['message', '@message']`. +| `xpack.infra.sources.default.fields.message` + | Fields used to display messages in the Logs app. Defaults to `['message', '@message']`. -`xpack.infra.sources.default.fields.tiebreaker`:: Field used to break ties between two entries with the same timestamp. Defaults to `_doc`. +| `xpack.infra.sources.default.fields.tiebreaker` + | Field used to break ties between two entries with the same timestamp. Defaults to `_doc`. -`xpack.infra.sources.default.fields.host`:: Field used to identify hosts. Defaults to `host.name`. +| `xpack.infra.sources.default.fields.host` + | Field used to identify hosts. Defaults to `host.name`. -`xpack.infra.sources.default.fields.container`:: Field used to identify Docker containers. Defaults to `container.id`. +| `xpack.infra.sources.default.fields.container` + | Field used to identify Docker containers. Defaults to `container.id`. -`xpack.infra.sources.default.fields.pod`:: Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. +| `xpack.infra.sources.default.fields.pod` + | Field used to identify Kubernetes pods. Defaults to `kubernetes.pod.uid`. + +|=== diff --git a/docs/settings/graph-settings.asciidoc b/docs/settings/graph-settings.asciidoc index 7e597362b1cfc..8ccff21a26f74 100644 --- a/docs/settings/graph-settings.asciidoc +++ b/docs/settings/graph-settings.asciidoc @@ -10,5 +10,10 @@ You do not need to configure any settings to use the {graph-features}. [float] [[general-graph-settings]] ==== General graph settings -`xpack.graph.enabled`:: -Set to `false` to disable the {graph-features}. + +[cols="2*<"] +|=== +| `xpack.graph.enabled` + | Set to `false` to disable the {graph-features}. + +|=== diff --git a/docs/settings/i18n-settings.asciidoc b/docs/settings/i18n-settings.asciidoc index 4fe466bcb4580..6d92e74f17cb2 100644 --- a/docs/settings/i18n-settings.asciidoc +++ b/docs/settings/i18n-settings.asciidoc @@ -9,10 +9,7 @@ You do not need to configure any settings to run Kibana in English. ==== General i18n Settings `i18n.locale`:: -Kibana currently supports the following locales: -+ -- English - `en` (default) -- Chinese - `zh-CN` -- Japanese - `ja-JP` - - + {kib} supports the following locales: + * English - `en` (default) + * Chinese - `zh-CN` + * Japanese - `ja-JP` diff --git a/docs/settings/ml-settings.asciidoc b/docs/settings/ml-settings.asciidoc index 36578c909f513..24e38e73bca9b 100644 --- a/docs/settings/ml-settings.asciidoc +++ b/docs/settings/ml-settings.asciidoc @@ -11,12 +11,25 @@ enabled by default. [[general-ml-settings-kb]] ==== General {ml} settings -`xpack.ml.enabled`:: -Set to `true` (default) to enable {kib} {ml-features}. + -+ -If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} -instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, -you can still use the {ml} APIs. To disable {ml} entirely, see the -{ref}/ml-settings.html[{es} {ml} settings]. +[cols="2*<"] +|=== +| `xpack.ml.enabled` + | Set to `true` (default) to enable {kib} {ml-features}. + + + + If set to `false` in `kibana.yml`, the {ml} icon is hidden in this {kib} + instance. If `xpack.ml.enabled` is set to `true` in `elasticsearch.yml`, however, + you can still use the {ml} APIs. To disable {ml} entirely, see the + {ref}/ml-settings.html[{es} {ml} settings]. +|=== +[[data-visualizer-settings]] +==== {data-viz} settings + +[cols="2*<"] +|=== +| `xpack.ml.file_data_visualizer.max_file_size` + | Sets the file size limit when importing data in the {data-viz}. The default + value is `100MB`. The highest supported value for this setting is `1GB`. + +|=== diff --git a/docs/settings/monitoring-settings.asciidoc b/docs/settings/monitoring-settings.asciidoc index 6645f49029a51..f180f2c3ecc97 100644 --- a/docs/settings/monitoring-settings.asciidoc +++ b/docs/settings/monitoring-settings.asciidoc @@ -29,45 +29,49 @@ For more information, see [[monitoring-general-settings]] ==== General monitoring settings -`monitoring.enabled`:: -Set to `true` (default) to enable the {monitor-features} in {kib}. Unlike the -`monitoring.ui.enabled` setting, when this setting is `false`, the -monitoring back-end does not run and {kib} stats are not sent to the monitoring -cluster. - -`monitoring.ui.elasticsearch.hosts`:: -Specifies the location of the {es} cluster where your monitoring data is stored. -By default, this is the same as `elasticsearch.hosts`. This setting enables -you to use a single {kib} instance to search and visualize data in your -production cluster as well as monitor data sent to a dedicated monitoring -cluster. - -`monitoring.ui.elasticsearch.username`:: -Specifies the username used by {kib} monitoring to establish a persistent connection -in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} -monitoring cluster. - -Every other request performed by the Stack Monitoring UI to the monitoring {es} -cluster uses the authenticated user's credentials, which must be the same on -both the {es} monitoring cluster and the {es} production cluster. - -If not set, {kib} uses the value of the `elasticsearch.username` setting. - -`monitoring.ui.elasticsearch.password`:: -Specifies the password used by {kib} monitoring to establish a persistent connection -in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} -monitoring cluster. - -Every other request performed by the Stack Monitoring UI to the monitoring {es} -cluster uses the authenticated user's credentials, which must be the same on -both the {es} monitoring cluster and the {es} production cluster. - -If not set, {kib} uses the value of the `elasticsearch.password` setting. - -`monitoring.ui.elasticsearch.pingTimeout`:: -Specifies the time in milliseconds to wait for {es} to respond to internal -health checks. By default, it matches the `elasticsearch.pingTimeout` setting, -which has a default value of `30000`. +[cols="2*<"] +|=== +| `monitoring.enabled` + | Set to `true` (default) to enable the {monitor-features} in {kib}. Unlike the + `monitoring.ui.enabled` setting, when this setting is `false`, the + monitoring back-end does not run and {kib} stats are not sent to the monitoring + cluster. + +| `monitoring.ui.elasticsearch.hosts` + | Specifies the location of the {es} cluster where your monitoring data is stored. + By default, this is the same as `elasticsearch.hosts`. This setting enables + you to use a single {kib} instance to search and visualize data in your + production cluster as well as monitor data sent to a dedicated monitoring + cluster. + +| `monitoring.ui.elasticsearch.username` + | Specifies the username used by {kib} monitoring to establish a persistent connection + in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} + monitoring cluster. + + + + Every other request performed by the Stack Monitoring UI to the monitoring {es} + cluster uses the authenticated user's credentials, which must be the same on + both the {es} monitoring cluster and the {es} production cluster. + + + + If not set, {kib} uses the value of the `elasticsearch.username` setting. + +| `monitoring.ui.elasticsearch.password` + | Specifies the password used by {kib} monitoring to establish a persistent connection + in {kib} to the {es} monitoring cluster and to verify licensing status on the {es} + monitoring cluster. + + + + Every other request performed by the Stack Monitoring UI to the monitoring {es} + cluster uses the authenticated user's credentials, which must be the same on + both the {es} monitoring cluster and the {es} production cluster. + + + + If not set, {kib} uses the value of the `elasticsearch.password` setting. + +| `monitoring.ui.elasticsearch.pingTimeout` + | Specifies the time in milliseconds to wait for {es} to respond to internal + health checks. By default, it matches the `elasticsearch.pingTimeout` setting, + which has a default value of `30000`. + +|=== [float] [[monitoring-collection-settings]] @@ -75,15 +79,18 @@ which has a default value of `30000`. These settings control how data is collected from {kib}. -`monitoring.kibana.collection.enabled`:: -Set to `true` (default) to enable data collection from the {kib} NodeJS server -for {kib} Dashboards to be featured in the Monitoring. +[cols="2*<"] +|=== +| `monitoring.kibana.collection.enabled` + | Set to `true` (default) to enable data collection from the {kib} NodeJS server + for {kib} Dashboards to be featured in the Monitoring. -`monitoring.kibana.collection.interval`:: -Specifies the number of milliseconds to wait in between data sampling on the -{kib} NodeJS server for the metrics that are displayed in the {kib} dashboards. -Defaults to `10000` (10 seconds). +| `monitoring.kibana.collection.interval` + | Specifies the number of milliseconds to wait in between data sampling on the + {kib} NodeJS server for the metrics that are displayed in the {kib} dashboards. + Defaults to `10000` (10 seconds). +|=== [float] [[monitoring-ui-settings]] @@ -94,27 +101,31 @@ However, the defaults work best in most circumstances. For more information about configuring {kib}, see {kibana-ref}/settings.html[Setting Kibana Server Properties]. -`monitoring.ui.elasticsearch.logFetchCount`:: -Specifies the number of log entries to display in the Monitoring UI. Defaults to -`10`. The maximum value is `50`. +[cols="2*<"] +|=== +| `monitoring.ui.elasticsearch.logFetchCount` + | Specifies the number of log entries to display in the Monitoring UI. Defaults to + `10`. The maximum value is `50`. -`monitoring.ui.max_bucket_size`:: -Specifies the number of term buckets to return out of the overall terms list when -performing terms aggregations to retrieve index and node metrics. For more -information about the `size` parameter, see -{ref}/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-size[Terms Aggregation]. -Defaults to `10000`. +| `monitoring.ui.max_bucket_size` + | Specifies the number of term buckets to return out of the overall terms list when + performing terms aggregations to retrieve index and node metrics. For more + information about the `size` parameter, see + {ref}/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-size[Terms Aggregation]. + Defaults to `10000`. -`monitoring.ui.min_interval_seconds`:: -Specifies the minimum number of seconds that a time bucket in a chart can -represent. Defaults to 10. If you modify the -`monitoring.ui.collection.interval` in `elasticsearch.yml`, use the same -value in this setting. +| `monitoring.ui.min_interval_seconds` + | Specifies the minimum number of seconds that a time bucket in a chart can + represent. Defaults to 10. If you modify the + `monitoring.ui.collection.interval` in `elasticsearch.yml`, use the same + value in this setting. -`monitoring.ui.enabled`:: -Set to `false` to hide the Monitoring UI in {kib}. The monitoring back-end -continues to run as an agent for sending {kib} stats to the monitoring -cluster. Defaults to `true`. +| `monitoring.ui.enabled` + | Set to `false` to hide the Monitoring UI in {kib}. The monitoring back-end + continues to run as an agent for sending {kib} stats to the monitoring + cluster. Defaults to `true`. + +|=== [float] [[monitoring-ui-cgroup-settings]] @@ -125,18 +136,20 @@ better decisions about your container performance, rather than guessing based on the overall machine performance. If you are not running your applications in a container, then Cgroup statistics are not useful. -`monitoring.ui.container.elasticsearch.enabled`:: - -For {es} clusters that are running in containers, this setting changes the -*Node Listing* to display the CPU utilization based on the reported Cgroup -statistics. It also adds the calculated Cgroup CPU utilization to the -*Node Overview* page instead of the overall operating system's CPU -utilization. Defaults to `false`. - -`monitoring.ui.container.logstash.enabled`:: - -For {ls} nodes that are running in containers, this setting -changes the {ls} *Node Listing* to display the CPU utilization -based on the reported Cgroup statistics. It also adds the -calculated Cgroup CPU utilization to the {ls} node detail -pages instead of the overall operating system’s CPU utilization. Defaults to `false`. +[cols="2*<"] +|=== +| `monitoring.ui.container.elasticsearch.enabled` + | For {es} clusters that are running in containers, this setting changes the + *Node Listing* to display the CPU utilization based on the reported Cgroup + statistics. It also adds the calculated Cgroup CPU utilization to the + *Node Overview* page instead of the overall operating system's CPU + utilization. Defaults to `false`. + +| `monitoring.ui.container.logstash.enabled` + | For {ls} nodes that are running in containers, this setting + changes the {ls} *Node Listing* to display the CPU utilization + based on the reported Cgroup statistics. It also adds the + calculated Cgroup CPU utilization to the {ls} node detail + pages instead of the overall operating system’s CPU utilization. Defaults to `false`. + +|=== diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc index 9a45fb9ab1d0c..7c50dbf542d0d 100644 --- a/docs/settings/reporting-settings.asciidoc +++ b/docs/settings/reporting-settings.asciidoc @@ -14,45 +14,54 @@ You can configure `xpack.reporting` settings in your `kibana.yml` to: [float] [[general-reporting-settings]] ==== General reporting settings -[[xpack-enable-reporting]]`xpack.reporting.enabled`:: -Set to `false` to disable the {report-features}. -`xpack.reporting.encryptionKey`:: -Set to any text string. By default, Kibana will generate a random key when it -starts, which will cause pending reports to fail after restart. Configure this -setting to preserve the same key across multiple restarts and multiple instances of Kibana. +[cols="2*<"] +|=== +| [[xpack-enable-reporting]]`xpack.reporting.enabled` + | Set to `false` to disable the {report-features}. + +| `xpack.reporting.encryptionKey` + | Set to any text string. By default, {kib} will generate a random key when it + starts, which will cause pending reports to fail after restart. Configure this + setting to preserve the same key across multiple restarts and multiple instances of {kib}. + +|=== [float] [[reporting-kibana-server-settings]] -==== Kibana server settings +==== {kib} server settings -Reporting opens the {kib} web interface in a server process to generate -screenshots of {kib} visualizations. In most cases, the default settings -will work and you don't need to configure Reporting to communicate with {kib}. +Reporting opens the {kib} web interface in a server process to generate +screenshots of {kib} visualizations. In most cases, the default settings +will work and you don't need to configure Reporting to communicate with {kib}. However, if your client connections must go through a reverse-proxy -to access {kib}, Reporting configuration must have the proxy port, protocol, +to access {kib}, Reporting configuration must have the proxy port, protocol, and hostname set in the `xpack.reporting.kibanaServer.*` settings. -[NOTE] +[NOTE] ==== -If a reverse-proxy carries encrypted traffic from end-user -clients back to a {kib} server, the proxy port, protocol, and hostname -in Reporting settings must be valid for the encryption that the Reporting -browser will receive. Encrypted communications will fail if there are +If a reverse-proxy carries encrypted traffic from end-user +clients back to a {kib} server, the proxy port, protocol, and hostname +in Reporting settings must be valid for the encryption that the Reporting +browser will receive. Encrypted communications will fail if there are mismatches in the host information between the request and the certificate on the server. Configuring the `xpack.reporting.kibanaServer` settings to point to a -proxy host requires that the Kibana server has network access to the proxy. +proxy host requires that the {kib} server has network access to the proxy. ==== -`xpack.reporting.kibanaServer.port`:: -The port for accessing Kibana, if different from the `server.port` value. +[cols="2*<"] +|=== +| `xpack.reporting.kibanaServer.port` + | The port for accessing {kib}, if different from the `server.port` value. + +| `xpack.reporting.kibanaServer.protocol` + | The protocol for accessing {kib}, typically `http` or `https`. -`xpack.reporting.kibanaServer.protocol`:: -The protocol for accessing Kibana, typically `http` or `https`. +| `xpack.reporting.kibanaServer.hostname` + | The hostname for accessing {kib}, if different from the `server.host` value. -`xpack.reporting.kibanaServer.hostname`:: -The hostname for accessing {kib}, if different from the `server.host` value. +|=== [NOTE] ============ @@ -68,55 +77,67 @@ because, in the Reporting browser, it becomes an automatic redirect to `"0.0.0.0 ==== Background job settings Reporting generates reports in the background and jobs are coordinated using documents -in Elasticsearch. Depending on how often you generate reports and the overall number of +in {es}. Depending on how often you generate reports and the overall number of reports, you might need to change the following settings. -`xpack.reporting.queue.indexInterval`:: -How often the index that stores reporting jobs rolls over to a new index. -Valid values are `year`, `month`, `week`, `day`, and `hour`. Defaults to `week`. +[cols="2*<"] +|=== +| `xpack.reporting.queue.indexInterval` + | How often the index that stores reporting jobs rolls over to a new index. + Valid values are `year`, `month`, `week`, `day`, and `hour`. Defaults to `week`. -`xpack.reporting.queue.pollEnabled`:: -Set to `true` (default) to enable the Kibana instance to to poll the index for -pending jobs and claim them for execution. Setting this to `false` allows the -Kibana instance to only add new jobs to the reporting queue, list jobs, and -provide the downloads to completed report through the UI. +| `xpack.reporting.queue.pollEnabled` + | Set to `true` (default) to enable the {kib} instance to to poll the index for + pending jobs and claim them for execution. Setting this to `false` allows the + {kib} instance to only add new jobs to the reporting queue, list jobs, and + provide the downloads to completed report through the UI. + +|=== [NOTE] ============ -Running multiple instances of Kibana in a cluster for load balancing of +Running multiple instances of {kib} in a cluster for load balancing of reporting requires identical values for `xpack.reporting.encryptionKey` and, if security is enabled, `xpack.security.encryptionKey`. ============ -`xpack.reporting.queue.pollInterval`:: -Specifies the number of milliseconds that the reporting poller waits between polling the -index for any pending Reporting jobs. Defaults to `3000` (3 seconds). +[cols="2*<"] +|=== +| `xpack.reporting.queue.pollInterval` + | Specifies the number of milliseconds that the reporting poller waits between polling the + index for any pending Reporting jobs. Defaults to `3000` (3 seconds). + +| [[xpack-reporting-q-timeout]] `xpack.reporting.queue.timeout` + | How long each worker has to produce a report. If your machine is slow or under + heavy load, you might need to increase this timeout. Specified in milliseconds. + If a Reporting job execution time goes over this time limit, the job will be + marked as a failure and there will not be a download available. + Defaults to `120000` (two minutes). -[[xpack-reporting-q-timeout]]`xpack.reporting.queue.timeout`:: -How long each worker has to produce a report. If your machine is slow or under -heavy load, you might need to increase this timeout. Specified in milliseconds. -If a Reporting job execution time goes over this time limit, the job will be -marked as a failure and there will not be a download available. -Defaults to `120000` (two minutes). +|=== [float] [[reporting-capture-settings]] ==== Capture settings -Reporting works by capturing screenshots from Kibana. The following settings +Reporting works by capturing screenshots from {kib}. The following settings control the capturing process. -`xpack.reporting.capture.timeouts.openUrl`:: -How long to allow the Reporting browser to wait for the initial data of the -Kibana page to load. Defaults to `30000` (30 seconds). +[cols="2*<"] +|=== +| `xpack.reporting.capture.timeouts.openUrl` + | How long to allow the Reporting browser to wait for the initial data of the + {kib} page to load. Defaults to `30000` (30 seconds). + +| `xpack.reporting.capture.timeouts.waitForElements` + | How long to allow the Reporting browser to wait for the visualization panels to + load on the {kib} page. Defaults to `30000` (30 seconds). -`xpack.reporting.capture.timeouts.waitForElements`:: -How long to allow the Reporting browser to wait for the visualization panels to -load on the Kibana page. Defaults to `30000` (30 seconds). +| `xpack.reporting.capture.timeouts.renderComplete` + | How long to allow the Reporting browser to wait for each visualization to + signal that it is done renderings. Defaults to `30000` (30 seconds). -`xpack.reporting.capture.timeouts.renderComplete`:: -How long to allow the Reporting brwoser to wait for each visualization to -signal that it is done renderings. Defaults to `30000` (30 seconds). +|=== [NOTE] ============ @@ -126,20 +147,24 @@ capturing the page with a screenshot. As a result, a download will be available, but there will likely be errors in the visualizations in the report. ============ -`xpack.reporting.capture.maxAttempts`:: -If capturing a report fails for any reason, Kibana will re-attempt othe reporting -job, as many times as this setting. Defaults to `3`. +[cols="2*<"] +|=== +| `xpack.reporting.capture.maxAttempts` + | If capturing a report fails for any reason, {kib} will re-attempt other reporting + job, as many times as this setting. Defaults to `3`. -`xpack.reporting.capture.loadDelay`:: -When visualizations are not evented, this is the amount of time before -taking a screenshot. All visualizations that ship with Kibana are evented, so this -setting should not have much effect. If you are seeing empty images instead of -visualizations, try increasing this value. -Defaults to `3000` (3 seconds). +| `xpack.reporting.capture.loadDelay` + | When visualizations are not evented, this is the amount of time before + taking a screenshot. All visualizations that ship with {kib} are evented, so this + setting should not have much effect. If you are seeing empty images instead of + visualizations, try increasing this value. + Defaults to `3000` (3 seconds). -[[xpack-reporting-browser]]`xpack.reporting.capture.browser.type`:: -Specifies the browser to use to capture screenshots. This setting exists for -backward compatibility. The only valid option is `chromium`. +| [[xpack-reporting-browser]] `xpack.reporting.capture.browser.type` + | Specifies the browser to use to capture screenshots. This setting exists for + backward compatibility. The only valid option is `chromium`. + +|=== [float] [[reporting-chromium-settings]] @@ -147,47 +172,59 @@ backward compatibility. The only valid option is `chromium`. When `xpack.reporting.capture.browser.type` is set to `chromium` (default) you can also specify the following settings. -`xpack.reporting.capture.browser.chromium.disableSandbox`:: -Elastic recommends that you research the feasibility of enabling unprivileged user namespaces. -See Chromium Sandbox for additional information. Defaults to false for all operating systems except Debian, -Red Hat Linux, and CentOS which use true +[cols="2*<"] +|=== +| `xpack.reporting.capture.browser.chromium.disableSandbox` + | It is recommended that you research the feasibility of enabling unprivileged user namespaces. + See Chromium Sandbox for additional information. Defaults to false for all operating systems except Debian, + Red Hat Linux, and CentOS which use true. -`xpack.reporting.capture.browser.chromium.proxy.enabled`:: -Enables the proxy for Chromium to use. When set to `true`, you must also specify the -`xpack.reporting.capture.browser.chromium.proxy.server` setting. -Defaults to `false` +| `xpack.reporting.capture.browser.chromium.proxy.enabled` + | Enables the proxy for Chromium to use. When set to `true`, you must also specify the + `xpack.reporting.capture.browser.chromium.proxy.server` setting. + Defaults to `false`. -`xpack.reporting.capture.browser.chromium.proxy.server`:: -The uri for the proxy server. Providing the username and password for the proxy server via the uri is not supported. +| `xpack.reporting.capture.browser.chromium.proxy.server` + | The uri for the proxy server. Providing the username and password for the proxy server via the uri is not supported. -`xpack.reporting.capture.browser.chromium.proxy.bypass`:: -An array of hosts that should not go through the proxy server and should use a direct connection instead. -Examples of valid entries are "elastic.co", "*.elastic.co", ".elastic.co", ".elastic.co:5601" +| `xpack.reporting.capture.browser.chromium.proxy.bypass` + | An array of hosts that should not go through the proxy server and should use a direct connection instead. + Examples of valid entries are "elastic.co", "*.elastic.co", ".elastic.co", ".elastic.co:5601". +|=== [float] [[reporting-csv-settings]] ==== CSV settings -[[xpack-reporting-csv]]`xpack.reporting.csv.maxSizeBytes`:: -The maximum size of a CSV file before being truncated. This setting exists to prevent -large exports from causing performance and storage issues. -Defaults to `10485760` (10mB) + +[cols="2*<"] +|=== +| [[xpack-reporting-csv]] `xpack.reporting.csv.maxSizeBytes` + | The maximum size of a CSV file before being truncated. This setting exists to prevent + large exports from causing performance and storage issues. + Defaults to `10485760` (10mB). + +|=== [float] [[reporting-advanced-settings]] ==== Advanced settings -`xpack.reporting.index`:: -Reporting uses a weekly index in Elasticsearch to store the reporting job and -the report content. The index is automatically created if it does not already -exist. Configure this to a unique value, beginning with `.reporting-`, for every -Kibana instance that has a unique `kibana.index` setting. Defaults to `.reporting` +[cols="2*<"] +|=== +| `xpack.reporting.index` + | Reporting uses a weekly index in {es} to store the reporting job and + the report content. The index is automatically created if it does not already + exist. Configure this to a unique value, beginning with `.reporting-`, for every + {kib} instance that has a unique `kibana.index` setting. Defaults to `.reporting`. + +| `xpack.reporting.roles.allow` + | Specifies the roles in addition to superusers that can use reporting. + Defaults to `[ "reporting_user" ]`. + -`xpack.reporting.roles.allow`:: -Specifies the roles in addition to superusers that can use reporting. -Defaults to `[ "reporting_user" ]` -+ --- -NOTE: Each user has access to only their own reports. +|=== --- +[NOTE] +============ +Each user has access to only their own reports. +============ diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index 16d68a7759f77..8f6905d643139 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -12,55 +12,83 @@ You do not need to configure any additional settings to use the [[general-security-settings]] ==== General security settings -`xpack.security.enabled`:: -By default, {kib} automatically detects whether to enable the -{security-features} based on the license and whether {es} {security-features} -are enabled. -+ -Do not set this to `false`; it disables the login form, user and role management -screens, and authorization using <>. To disable -{security-features} entirely, see -{ref}/security-settings.html[{es} security settings]. - -`xpack.security.audit.enabled`:: -Set to `true` to enable audit logging for security events. By default, it is set -to `false`. For more details see <>. +[cols="2*<"] +|=== +| `xpack.security.enabled` + | By default, {kib} automatically detects whether to enable the + {security-features} based on the license and whether {es} {security-features} + are enabled. + + + + Do not set this to `false`; it disables the login form, user and role management + screens, and authorization using <>. To disable + {security-features} entirely, see + {ref}/security-settings.html[{es} security settings]. + +| `xpack.security.audit.enabled` + | Set to `true` to enable audit logging for security events. By default, it is set + to `false`. For more details see <>. + +|=== [float] [[security-ui-settings]] ==== User interface security settings -You can configure the following settings in the `kibana.yml` file: - -`xpack.security.cookieName`:: -Sets the name of the cookie used for the session. The default value is `"sid"`. - -`xpack.security.encryptionKey`:: -An arbitrary string of 32 characters or more that is used to encrypt credentials -in a cookie. It is crucial that this key is not exposed to users of {kib}. By -default, a value is automatically generated in memory. If you use that default -behavior, all sessions are invalidated when {kib} restarts. -In addition, high-availability deployments of {kib} will behave unexpectedly -if this setting isn't the same for all instances of {kib}. - -`xpack.security.secureCookies`:: -Sets the `secure` flag of the session cookie. The default value is `false`. It -is automatically set to `true` if `server.ssl.enabled` is set to `true`. Set -this to `true` if SSL is configured outside of {kib} (for example, you are -routing requests through a load balancer or proxy). - -`xpack.security.session.idleTimeout`:: -Sets the session duration. The format is a string of `[ms|s|m|h|d|w|M|Y]` -(e.g. '70ms', '5s', '3d', '1Y'). By default, sessions stay active until the -browser is closed. When this is set to an explicit idle timeout, closing the -browser still requires the user to log back in to {kib}. - -`xpack.security.session.lifespan`:: -Sets the maximum duration, also known as "absolute timeout". The format is a -string of `[ms|s|m|h|d|w|M|Y]` (e.g. '70ms', '5s', '3d', '1Y'). By default, -a session can be renewed indefinitely. When this value is set, a session will end -once its lifespan is exceeded, even if the user is not idle. NOTE: if `idleTimeout` -is not set, this setting will still cause sessions to expire. - -`xpack.security.loginAssistanceMessage`:: -Adds a message to the login screen. Useful for displaying information about maintenance windows, links to corporate sign up pages etc. +You can configure the following settings in the `kibana.yml` file. + +[cols="2*<"] +|=== +| `xpack.security.cookieName` + | Sets the name of the cookie used for the session. The default value is `"sid"`. + +| `xpack.security.encryptionKey` + | An arbitrary string of 32 characters or more that is used to encrypt credentials + in a cookie. It is crucial that this key is not exposed to users of {kib}. By + default, a value is automatically generated in memory. If you use that default + behavior, all sessions are invalidated when {kib} restarts. + In addition, high-availability deployments of {kib} will behave unexpectedly + if this setting isn't the same for all instances of {kib}. + +| `xpack.security.secureCookies` + | Sets the `secure` flag of the session cookie. The default value is `false`. It + is automatically set to `true` if `server.ssl.enabled` is set to `true`. Set + this to `true` if SSL is configured outside of {kib} (for example, you are + routing requests through a load balancer or proxy). + +| `xpack.security.session.idleTimeout` + | Sets the session duration. By default, sessions stay active until the + browser is closed. When this is set to an explicit idle timeout, closing the + browser still requires the user to log back in to {kib}. + +|=== + +[TIP] +============ +The format is a string of `[ms|s|m|h|d|w|M|Y]` +(e.g. '70ms', '5s', '3d', '1Y'). +============ + +[cols="2*<"] +|=== + +| `xpack.security.session.lifespan` + | Sets the maximum duration, also known as "absolute timeout". By default, + a session can be renewed indefinitely. When this value is set, a session will end + once its lifespan is exceeded, even if the user is not idle. NOTE: if `idleTimeout` + is not set, this setting will still cause sessions to expire. + +|=== + +[TIP] +============ +The format is a +string of `[ms|s|m|h|d|w|M|Y]` (e.g. '70ms', '5s', '3d', '1Y'). +============ + +[cols="2*<"] +|=== + +| `xpack.security.loginAssistanceMessage` + | Adds a message to the login screen. Useful for displaying information about maintenance windows, links to corporate sign up pages etc. + +|=== diff --git a/docs/settings/spaces-settings.asciidoc b/docs/settings/spaces-settings.asciidoc index bb0a15b29a087..bda5f00f762cd 100644 --- a/docs/settings/spaces-settings.asciidoc +++ b/docs/settings/spaces-settings.asciidoc @@ -5,18 +5,22 @@ Spaces settings ++++ -By default, Spaces is enabled in Kibana, and you can secure Spaces using +By default, Spaces is enabled in Kibana, and you can secure Spaces using roles when Security is enabled. [float] [[spaces-settings]] ==== Spaces settings -`xpack.spaces.enabled`:: -Set to `true` (default) to enable Spaces in {kib}. +[cols="2*<"] +|=== +| `xpack.spaces.enabled` + | Set to `true` (default) to enable Spaces in {kib}. -`xpack.spaces.maxSpaces`:: -The maximum amount of Spaces that can be used with this instance of Kibana. Some operations -in Kibana return all spaces using a single `_search` from Elasticsearch, so this must be -set lower than the `index.max_result_window` in Elasticsearch. -Defaults to `1000`. \ No newline at end of file +| `xpack.spaces.maxSpaces` + | The maximum amount of Spaces that can be used with this instance of {kib}. Some operations + in {kib} return all spaces using a single `_search` from {es}, so this must be + set lower than the `index.max_result_window` in {es}. + Defaults to `1000`. + +|=== diff --git a/docs/settings/telemetry-settings.asciidoc b/docs/settings/telemetry-settings.asciidoc index ad5f53ad879f8..33f167b13b310 100644 --- a/docs/settings/telemetry-settings.asciidoc +++ b/docs/settings/telemetry-settings.asciidoc @@ -8,7 +8,7 @@ By default, Usage Collection (also known as Telemetry) is enabled. This helps us learn about the {kib} features that our users are most interested in, so we can focus our efforts on making them even better. -You can control whether this data is sent from the {kib} servers, or if it should be sent +You can control whether this data is sent from the {kib} servers, or if it should be sent from the user's browser, in case a firewall is blocking the connections from the server. Additionally, you can decide to completely disable this feature either in the config file or in {kib} via *Management > Kibana > Advanced Settings > Usage Data*. See our https://www.elastic.co/legal/privacy-statement[Privacy Statement] to learn more. @@ -17,22 +17,30 @@ See our https://www.elastic.co/legal/privacy-statement[Privacy Statement] to lea [[telemetry-general-settings]] ==== General telemetry settings -`telemetry.enabled`:: *Default: true*. -Set to `true` to send cluster statistics to Elastic. Reporting your -cluster statistics helps us improve your user experience. Your data is never -shared with anyone. Set to `false` to disable statistics reporting from any -browser connected to the {kib} instance. - -`telemetry.sendUsageFrom`:: *Default: 'browser'*. -Set to `'server'` to report the cluster statistics from the {kib} server. -If the server fails to connect to our endpoint at https://telemetry.elastic.co/, it assumes -it is behind a firewall and falls back to `'browser'` to send it from users' browsers -when they are navigating through {kib}. - -`telemetry.optIn`:: *Default: true*. -Set to `true` to automatically opt into reporting cluster statistics. You can also opt out through -*Advanced Settings* in {kib}. - -`telemetry.allowChangingOptInStatus`:: *Default: true*. -Set to `true` to allow overwriting the `telemetry.optIn` setting via the {kib} UI. -Note: When `false`, `telemetry.optIn` must be `true`. To disable telemetry and not allow users to change that parameter, use `telemetry.enabled`. +[cols="2*<"] +|=== +| `telemetry.enabled` + | Set to `true` to send cluster statistics to Elastic. Reporting your + cluster statistics helps us improve your user experience. Your data is never + shared with anyone. Set to `false` to disable statistics reporting from any + browser connected to the {kib} instance. Defaults to `true`. + +| `telemetry.sendUsageFrom` + | Set to `'server'` to report the cluster statistics from the {kib} server. + If the server fails to connect to our endpoint at https://telemetry.elastic.co/, it assumes + it is behind a firewall and falls back to `'browser'` to send it from users' browsers + when they are navigating through {kib}. Defaults to 'browser'. + +| `telemetry.optIn` + | Set to `true` to automatically opt into reporting cluster statistics. You can also opt out through + *Advanced Settings* in {kib}. Defaults to `true`. + +| `telemetry.allowChangingOptInStatus` + | Set to `true` to allow overwriting the `telemetry.optIn` setting via the {kib} UI. Defaults to `true`. + + +|=== + +[NOTE] +============ +When `false`, `telemetry.optIn` must be `true`. To disable telemetry and not allow users to change that parameter, use `telemetry.enabled`. +============ diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 41fe8d337c03b..cc662af08b8f1 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -1,7 +1,7 @@ [[settings]] -== Configuring Kibana +== Configuring {kib} -The Kibana server reads properties from the `kibana.yml` file on startup. The +The {kib} server reads properties from the `kibana.yml` file on startup. The location of this file differs depending on how you installed {kib}. For example, if you installed {kib} from an archive distribution (`.tar.gz` or `.zip`), by default it is in `$KIBANA_HOME/config`. By default, with package distributions @@ -11,444 +11,622 @@ The default host and port settings configure {kib} to run on `localhost:5601`. T variety of other options. Finally, environment variables can be injected into configuration using `${MY_ENV_VAR}` syntax. -.Kibana configuration settings +[cols="2*<"] +|=== -`console.enabled:`:: *Default: true* Set to false to disable Console. Toggling -this will cause the server to regenerate assets on the next startup, which may -cause a delay before pages start being served. +| `console.enabled:` + | Toggling this causes the server to regenerate assets on the next startup, +which may cause a delay before pages start being served. +Set to `false` to disable Console. *Default: `true`* -`cpu.cgroup.path.override:`:: Override for cgroup cpu path when mounted in a -manner that is inconsistent with `/proc/self/cgroup` +| `cpu.cgroup.path.override:` + | Override for cgroup cpu path when mounted in a +manner that is inconsistent with `/proc/self/cgroup`. -`cpuacct.cgroup.path.override:`:: Override for cgroup cpuacct path when mounted -in a manner that is inconsistent with `/proc/self/cgroup` +| `cpuacct.cgroup.path.override:` + | Override for cgroup cpuacct path when mounted +in a manner that is inconsistent with `/proc/self/cgroup`. -`csp.rules:`:: A template -https://w3c.github.io/webappsec-csp/[content-security-policy] that disables -certain unnecessary and potentially insecure capabilities in the browser. We -strongly recommend that you keep the default CSP rules that ship with Kibana. +| `csp.rules:` + | A https://w3c.github.io/webappsec-csp/[content-security-policy] template +that disables certain unnecessary and potentially insecure capabilities in +the browser. It is strongly recommended that you keep the default CSP rules +that ship with {kib}. -`csp.strict:`:: *Default: `true`* Blocks access to Kibana to any browser that -does not enforce even rudimentary CSP rules. In practice, this will disable +| `csp.strict:` + | Blocks {kib} access to any browser that +does not enforce even rudimentary CSP rules. In practice, this disables support for older, less safe browsers like Internet Explorer. -See <> for more information. - -`csp.warnLegacyBrowsers:`:: *Default: `true`* Shows a warning message after -loading Kibana to any browser that does not enforce even rudimentary CSP rules, -though Kibana is still accessible. This configuration is effectively ignored -when `csp.strict` is enabled. - -`elasticsearch.customHeaders:`:: *Default: `{}`* Header names and values to send -to Elasticsearch. Any custom headers cannot be overwritten by client-side -headers, regardless of the `elasticsearch.requestHeadersWhitelist` configuration. - -`elasticsearch.hosts:`:: *Default: `[ "http://localhost:9200" ]`* The URLs of the {es} instances to use for all your queries. All nodes -listed here must be on the same cluster. +For more information, refer to <>. +*Default: `true`* + +| `csp.warnLegacyBrowsers:` + | Shows a warning message after loading {kib} to any browser that does not +enforce even rudimentary CSP rules, though {kib} is still accessible. This +configuration is effectively ignored when `csp.strict` is enabled. +*Default: `true`* + +| `elasticsearch.customHeaders:` + | Header names and values to send to {es}. Any custom headers cannot be +overwritten by client-side headers, regardless of the +`elasticsearch.requestHeadersWhitelist` configuration. *Default: `{}`* + +| `elasticsearch.hosts:` + | The URLs of the {es} instances to use for all your queries. All nodes +listed here must be on the same cluster. *Default: `[ "http://localhost:9200" ]`* + -To enable SSL/TLS for outbound connections to {es}, use the `https` protocol in this setting. - -`elasticsearch.logQueries:`:: *Default: `false`* Logs queries sent to -Elasticsearch. Requires `logging.verbose` set to `true`. This is useful for -seeing the query DSL generated by applications that currently do not have an -inspector, for example Timelion and Monitoring. - -`elasticsearch.pingTimeout:`:: -*Default: the value of the `elasticsearch.requestTimeout` setting* Time in -milliseconds to wait for Elasticsearch to respond to pings. - -`elasticsearch.preserveHost:`:: *Default: true* When this setting’s value is -true, Kibana uses the hostname specified in the `server.host` setting. When the -value of this setting is `false`, Kibana uses the hostname of the host that -connects to this Kibana instance. - -`elasticsearch.requestHeadersWhitelist:`:: *Default: `[ 'authorization' ]`* List -of Kibana client-side headers to send to Elasticsearch. To send *no* client-side -headers, set this value to [] (an empty list). -Removing the `authorization` header from being whitelisted means that you cannot -use <> in Kibana. - -`elasticsearch.requestTimeout:`:: *Default: 30000* Time in milliseconds to wait -for responses from the back end or Elasticsearch. This value must be a positive -integer. - -`elasticsearch.shardTimeout:`:: *Default: 30000* Time in milliseconds for -Elasticsearch to wait for responses from shards. Set to 0 to disable. - -`elasticsearch.sniffInterval:`:: *Default: false* Time in milliseconds between -requests to check Elasticsearch for an updated list of nodes. - -`elasticsearch.sniffOnStart:`:: *Default: false* Attempt to find other -Elasticsearch nodes on startup. - -`elasticsearch.sniffOnConnectionFault:`:: *Default: false* Update the list of -Elasticsearch nodes immediately following a connection fault. - -`elasticsearch.ssl.alwaysPresentCertificate:`:: *Default: false* Controls {kib}'s behavior in regard to presenting a client certificate when -requested by {es}. This setting applies to all outbound SSL/TLS connections to {es}, including requests that are proxied for end users. -+ -WARNING: If {es} uses certificates to authenticate end users with a PKI realm and `elasticsearch.ssl.alwaysPresentCertificate` is `true`, -proxied requests may be executed as the identity that is tied to the {kib} server. - -`elasticsearch.ssl.certificate:` and `elasticsearch.ssl.key:`:: Paths to a PEM-encoded X.509 client certificate and its corresponding -private key. These are used by {kib} to authenticate itself when making outbound SSL/TLS connections to {es}. For this setting to take -effect, the `xpack.security.http.ssl.client_authentication` setting in {es} must be also be set to `"required"` or `"optional"` to request a -client certificate from {kib}. +To enable SSL/TLS for outbound connections to {es}, use the `https` protocol +in this setting. + +| `elasticsearch.logQueries:` + | Log queries sent to {es}. Requires `logging.verbose` set to `true`. +This is useful for seeing the query DSL generated by applications that +currently do not have an inspector, for example Timelion and Monitoring. +*Default: `false`* + +| `elasticsearch.pingTimeout:` + | Time in milliseconds to wait for {es} to respond to pings. +*Default: the value of the `elasticsearch.requestTimeout` setting* + +| `elasticsearch.preserveHost:` + | When the value is `true`, {kib} uses the hostname specified in the +`server.host` setting. When the value is `false`, {kib} uses +the hostname of the host that connects to this {kib} instance. *Default: `true`* + +| `elasticsearch.requestHeadersWhitelist:` + | List of {kib} client-side headers to send to {es}. To send *no* client-side +headers, set this value to [] (an empty list). Removing the `authorization` +header from being whitelisted means that you cannot use +<> in {kib}. +*Default: `[ 'authorization' ]`* + +| `elasticsearch.requestTimeout:` + | Time in milliseconds to wait for responses from the back end or {es}. +This value must be a positive integer. *Default: `30000`* + +| `elasticsearch.shardTimeout:` + | Time in milliseconds for {es} to wait for responses from shards. +Set to 0 to disable. *Default: `30000`* + +| `elasticsearch.sniffInterval:` + | Time in milliseconds between requests to check {es} for an updated list of +nodes. *Default: `false`* + +| `elasticsearch.sniffOnStart:` + | Attempt to find other {es} nodes on startup. *Default: `false`* + +| `elasticsearch.sniffOnConnectionFault:` + | Update the list of {es} nodes immediately following a connection fault. +*Default: `false`* + +| `elasticsearch.ssl.alwaysPresentCertificate:` + | Controls {kib} behavior in regard to presenting a client certificate when +requested by {es}. This setting applies to all outbound SSL/TLS connections +to {es}, including requests that are proxied for end users. *Default: `false`* + +|=== + +[WARNING] +============ +When {es} uses certificates to authenticate end users with a PKI realm +and `elasticsearch.ssl.alwaysPresentCertificate` is `true`, +proxied requests may be executed as the identity that is tied to the {kib} +server. +============ + +[cols="2*<"] +|=== + +| `elasticsearch.ssl.certificate:` and `elasticsearch.ssl.key:` + | Paths to a PEM-encoded X.509 client certificate and its corresponding +private key. These are used by {kib} to authenticate itself when making +outbound SSL/TLS connections to {es}. For this setting to take effect, the +`xpack.security.http.ssl.client_authentication` setting in {es} must be also +be set to `"required"` or `"optional"` to request a client certificate from +{kib}. + +|=== + +[NOTE] +============ +These settings cannot be used in conjunction with `elasticsearch.ssl.keystore.path`. +============ + +[cols="2*<"] +|=== + +| `elasticsearch.ssl.certificateAuthorities:` + | Paths to one or more PEM-encoded X.509 certificate authority (CA) +certificates, which make up a trusted certificate chain for {es}. This chain is +used by {kib} to establish trust when making outbound SSL/TLS connections to +{es}. + -NOTE: These settings cannot be used in conjunction with `elasticsearch.ssl.keystore.path`. - -`elasticsearch.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates which make up a -trusted certificate chain for {es}. This chain is used by {kib} to establish trust when making outbound SSL/TLS connections to {es}. +In addition to this setting, trusted certificates may be specified via +`elasticsearch.ssl.keystore.path` and/or `elasticsearch.ssl.truststore.path`. + +| `elasticsearch.ssl.keyPassphrase:` + | The password that decrypts the private key that is specified +via `elasticsearch.ssl.key`. This value is optional, as the key may not be +encrypted. + +| `elasticsearch.ssl.keystore.path:` + | Path to a PKCS#12 keystore that contains an X.509 client certificate and it's +corresponding private key. These are used by {kib} to authenticate itself when +making outbound SSL/TLS connections to {es}. For this setting, you must also set +the `xpack.security.http.ssl.client_authentication` setting in {es} to +`"required"` or `"optional"` to request a client certificate from {kib}. + -In addition to this setting, trusted certificates may be specified via `elasticsearch.ssl.keystore.path` and/or +If the keystore contains any additional certificates, they are used as a +trusted certificate chain for {es}. This chain is used by {kib} to establish +trust when making outbound SSL/TLS connections to {es}. In addition to this +setting, trusted certificates may be specified via +`elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.truststore.path`. -`elasticsearch.ssl.keyPassphrase:`:: The password that will be used to decrypt the private key that is specified via -`elasticsearch.ssl.key`. This value is optional, as the key may not be encrypted. +|=== -`elasticsearch.ssl.keystore.path:`:: Path to a PKCS#12 keystore that contains an X.509 client certificate and its corresponding private key. -These are used by {kib} to authenticate itself when making outbound SSL/TLS connections to {es}. For this setting to take effect, the -`xpack.security.http.ssl.client_authentication` setting in {es} must also be set to `"required"` or `"optional"` to request a client -certificate from {kib}. -+ --- -If the keystore contains any additional certificates, those will be used as a trusted certificate chain for {es}. This chain is used by -{kib} to establish trust when making outbound SSL/TLS connections to {es}. In addition to this setting, trusted certificates may be -specified via `elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.truststore.path`. +[NOTE] +============ +This setting cannot be used in conjunction with +`elasticsearch.ssl.certificate` or `elasticsearch.ssl.key`. +============ -NOTE: This setting cannot be used in conjunction with `elasticsearch.ssl.certificate` or `elasticsearch.ssl.key`. --- +[cols="2*<"] +|=== -`elasticsearch.ssl.keystore.password:`:: The password that will be used to decrypt the keystore that is specified via -`elasticsearch.ssl.keystore.path`. If the keystore has no password, leave this unset. If the keystore has an empty password, set this to +| `elasticsearch.ssl.keystore.password:` + | The password that decrypts the keystore specified via +`elasticsearch.ssl.keystore.path`. If the keystore has no password, leave this +as blank. If the keystore has an empty password, set this to `""`. -`elasticsearch.ssl.truststore.path:`:: Path to a PKCS#12 trust store that contains one or more X.509 certificate authority (CA) certificates -which make up a trusted certificate chain for {es}. This chain is used by {kib} to establish trust when making outbound SSL/TLS connections -to {es}. +| `elasticsearch.ssl.truststore.path:`:: + | Path to a PKCS#12 trust store that contains one or more X.509 certificate +authority (CA) certificates, which make up a trusted certificate chain for +{es}. This chain is used by {kib} to establish trust when making outbound +SSL/TLS connections to {es}. + -In addition to this setting, trusted certificates may be specified via `elasticsearch.ssl.certificateAuthorities` and/or +In addition to this setting, trusted certificates may be specified via +`elasticsearch.ssl.certificateAuthorities` and/or `elasticsearch.ssl.keystore.path`. -`elasticsearch.ssl.truststore.password:`:: The password that will be used to decrypt the trust store specified via -`elasticsearch.ssl.truststore.path`. If the trust store has no password, leave this unset. If the trust store has an empty password, set -this to `""`. - -`elasticsearch.ssl.verificationMode:`:: *Default: `"full"`* Controls the verification of the server certificate that {kib} receives when -making an outbound SSL/TLS connection to {es}. Valid values are `"full"`, `"certificate"`, and `"none"`. Using `"full"` will perform -hostname verification, using `"certificate"` will skip hostname verification, and using `"none"` will skip verification entirely. - -`elasticsearch.startupTimeout:`:: *Default: 5000* Time in milliseconds to wait -for Elasticsearch at Kibana startup before retrying. - -`elasticsearch.username:` and `elasticsearch.password:`:: If your Elasticsearch -is protected with basic authentication, these settings provide the username and -password that the Kibana server uses to perform maintenance on the Kibana index -at startup. Your Kibana users still need to authenticate with Elasticsearch, -which is proxied through the Kibana server. - -`interpreter.enableInVisualize`:: *Default: true* Enables use of interpreter in -Visualize. - -`kibana.defaultAppId:`:: *Default: "home"* The default application to load. - -`kibana.index:`:: *Default: ".kibana"* Kibana uses an index in Elasticsearch to -store saved searches, visualizations and dashboards. Kibana creates a new index -if the index doesn’t already exist. If you configure a custom index, the name must -be lowercase, and conform to {es} {ref}/indices-create-index.html[index name limitations]. - -`kibana.autocompleteTimeout:`:: *Default: "1000"* Time in milliseconds to wait -for autocomplete suggestions from Elasticsearch. This value must be a whole number -greater than zero. - -`kibana.autocompleteTerminateAfter:`:: *Default: "100000"* Maximum number of -documents loaded by each shard to generate autocomplete suggestions. This value -must be a whole number greater than zero. - -`logging.dest:`:: *Default: `stdout`* Enables you specify a file where Kibana -stores log output. - -`logging.json:`:: *Default: false* Logs output as JSON. When set to `true`, the -logs will be formatted as JSON strings that include timestamp, log level, context, message -text and any other metadata that may be associated with the log message itself. -If `logging.dest.stdout` is set and there is no interactive terminal ("TTY"), this setting -will default to `true`. - -`logging.quiet:`:: *Default: false* Set the value of this setting to `true` to -suppress all logging output other than error messages. - -`logging.rotate:`:: [experimental] Specifies the options for the logging rotate feature. +|`elasticsearch.ssl.truststore.password:` + | The password that decrypts the trust store specified via +`elasticsearch.ssl.truststore.path`. If the trust store has no password, +leave this as blank. If the trust store has an empty password, set this to `""`. + +| `elasticsearch.ssl.verificationMode:` + | Controls the verification of the server certificate that {kib} receives when +making an outbound SSL/TLS connection to {es}. Valid values are `"full"`, +`"certificate"`, and `"none"`. Using `"full"` performs hostname verification, +using `"certificate"` skips hostname verification, and using `"none"` skips +verification entirely. *Default: `"full"`* + +| `elasticsearch.startupTimeout:` + | Time in milliseconds to wait for {es} at {kib} startup before retrying. +*Default: `5000`* + +| `elasticsearch.username:` and `elasticsearch.password:` + | If your {es} is protected with basic authentication, these settings provide +the username and password that the {kib} server uses to perform maintenance +on the {kib} index at startup. {kib} users still need to authenticate with +{es}, which is proxied through the {kib} server. + +| `interpreter.enableInVisualize` + | Enables use of interpreter in Visualize. *Default: `true`* + +| `kibana.defaultAppId:` + | The default application to load. *Default: `"home"`* + +| `kibana.index:` + | {kib} uses an index in {es} to store saved searches, visualizations, and +dashboards. {kib} creates a new index if the index doesn’t already exist. +If you configure a custom index, the name must be lowercase, and conform to the +{es} {ref}/indices-create-index.html[index name limitations]. +*Default: `".kibana"`* + +| `kibana.autocompleteTimeout:` + | Time in milliseconds to wait for autocomplete suggestions from {es}. +This value must be a whole number greater than zero. *Default: `"1000"`* + +| `kibana.autocompleteTerminateAfter:` + | Maximum number of documents loaded by each shard to generate autocomplete +suggestions. This value must be a whole number greater than zero. +*Default: `"100000"`* + +| `logging.dest:` + | Enables you to specify a file where {kib} stores log output. +*Default: `stdout`* + +| `logging.json:` + | Logs output as JSON. When set to `true`, the logs are formatted as JSON +strings that include timestamp, log level, context, message text, and any other +metadata that may be associated with the log message. +When `logging.dest.stdout` is set, and there is no interactive terminal ("TTY"), +this setting defaults to `true`. *Default: `false`* + +| `logging.quiet:` + | Set the value of this setting to `true` to suppress all logging output other +than error messages. *Default: `false`* + +| `logging.rotate:` + | experimental[] Specifies the options for the logging rotate feature. When not defined, all the sub options defaults would be applied. The following example shows a valid logging rotate configuration: -+ + +|=== + +[source,text] -- - logging.rotate: - enabled: true - everyBytes: 10485760 - keepFiles: 10 + logging.rotate: + enabled: true + everyBytes: 10485760 + keepFiles: 10 -- -`logging.rotate.enabled:`:: [experimental] *Default: false* Set the value of this setting to `true` to +[cols="2*<"] +|=== + +| `logging.rotate.enabled:` + | experimental[] Set the value of this setting to `true` to enable log rotation. If you do not have a `logging.dest` set that is different from `stdout` -that feature would not take any effect. +that feature would not take any effect. *Default: `false`* -`logging.rotate.everyBytes:`:: [experimental] *Default: 10485760* The maximum size of a log file (that is `not an exact` limit). After the +| `logging.rotate.everyBytes:` + | experimental[] The maximum size of a log file (that is `not an exact` limit). After the limit is reached, a new log file is generated. The default size limit is 10485760 (10 MB) and -this option should be in the range of 1048576 (1 MB) to 1073741824 (1 GB). +this option should be in the range of 1048576 (1 MB) to 1073741824 (1 GB). *Default: `10485760`* -`logging.rotate.keepFiles:`:: [experimental] *Default: 7* The number of most recent rotated log files to keep +| `logging.rotate.keepFiles:` + | experimental[] The number of most recent rotated log files to keep on disk. Older files are deleted during log rotation. The default value is 7. The `logging.rotate.keepFiles` -option has to be in the range of 2 to 1024 files. +option has to be in the range of 2 to 1024 files. *Default: `7`* -`logging.rotate.pollingInterval:`:: [experimental] *Default: 10000* The number of milliseconds for the polling strategy in case -the `logging.rotate.usePolling` is enabled. That option has to be in the range of 5000 to 3600000 milliseconds. +| `logging.rotate.pollingInterval:` + | experimental[] The number of milliseconds for the polling strategy in case +the `logging.rotate.usePolling` is enabled. `logging.rotate.usePolling` must be in the 5000 to 3600000 millisecond range. *Default: `10000`* -`logging.rotate.usePolling:`:: [experimental] *Default: false* By default we try to understand the best way to monitoring +| `logging.rotate.usePolling:` + | experimental[] By default we try to understand the best way to monitoring the log file and warning about it. Please be aware there are some systems where watch api is not accurate. In those cases, in order to get the feature working, -the `polling` method could be used enabling that option. +the `polling` method could be used enabling that option. *Default: `false`* -`logging.silent:`:: *Default: false* Set the value of this setting to `true` to -suppress all logging output. +| `logging.silent:` + | Set the value of this setting to `true` to +suppress all logging output. *Default: `false`* -`logging.timezone`:: *Default: UTC* Set to the canonical timezone id -(for example, `America/Los_Angeles`) to log events using that timezone. A list of timezones can -be referenced at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. +| `logging.timezone` + | Set to the canonical timezone ID +(for example, `America/Los_Angeles`) to log events using that timezone. For a +list of timezones, refer to https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. *Default: `UTC`* -[[logging-verbose]]`logging.verbose:`:: *Default: false* Set the value of this -setting to `true` to log all events, including system usage information and all -requests. Supported on Elastic Cloud Enterprise. +| [[logging-verbose]] `logging.verbose:` + | Set to `true` to log all events, including system usage information and all +requests. Supported on {ece}. *Default: `false`* -`map.includeElasticMapsService:`:: *Default: true* -Set to false to disable connections to Elastic Maps Service. +| `map.includeElasticMapsService:` + | Set to `false` to disable connections to Elastic Maps Service. When `includeElasticMapsService` is turned off, only the vector layers configured by `map.regionmap` -and the tile layer configured by `map.tilemap.url` will be available in <>. +and the tile layer configured by `map.tilemap.url` are available in <>. *Default: `true`* -`map.proxyElasticMapsServiceInMaps:`:: *Default: false* -Set to true to proxy all <> Elastic Maps Service requests through the Kibana server. +| `map.proxyElasticMapsServiceInMaps:` + | Set to `true` to proxy all <> Elastic Maps Service +requests through the {kib} server. *Default: `false`* -[[regionmap-settings]] `map.regionmap:`:: Specifies additional vector layers for +| [[regionmap-settings]] `map.regionmap:` + | Specifies additional vector layers for use in <> visualizations. Supported on {ece}. Each layer object points to an external vector file that contains a geojson FeatureCollection. The file must use the https://en.wikipedia.org/wiki/World_Geodetic_System[WGS84 coordinate reference system (ESPG:4326)] and only include polygons. If the file is hosted on a separate domain from -Kibana, the server needs to be CORS-enabled so Kibana can download the file. -[[region-map-configuration-example]] +{kib}, the server needs to be CORS-enabled so {kib} can download the file. The following example shows a valid region map configuration. -+ + +|=== + +[source,text] -- - map - includeElasticMapsService: false - regionmap: - layers: - - name: "Departments of France" - url: "http://my.cors.enabled.server.org/france_departements.geojson" - attribution: "INRAP" - fields: - - name: "department" - description: "Full department name" - - name: "INSEE" - description: "INSEE numeric identifier" +map.regionmap: + includeElasticMapsService: false + layers: + - name: "Departments of France" + url: "http://my.cors.enabled.server.org/france_departements.geojson" + attribution: "INRAP" + fields: + - name: "department" + description: "Full department name" + - name: "INSEE" + description: "INSEE numeric identifier" -- -[[regionmap-ES-map]]`map.includeElasticMapsService:`:: Turns on or off -whether layers from the Elastic Maps Service should be included in the vector -layer option list. Supported on Elastic Cloud Enterprise. By turning this off, +[cols="2*<"] +|=== + +| [[regionmap-ES-map]] `map.includeElasticMapsService:` + | Turns on or off whether layers from the Elastic Maps Service should be included in the vector +layer option list. Supported on {ece}. By turning this off, only the layers that are configured here will be included. The default is `true`. This also affects whether tile-service from the Elastic Maps Service will be available. -[[regionmap-attribution]]`map.regionmap.layers[].attribution:`:: Optional. -References the originating source of the geojson file. Supported on {ece}. +| [[regionmap-attribution]] `map.regionmap.layers[].attribution:` + | Optional. References the originating source of the geojson file. +Supported on {ece}. -[[regionmap-fields]]`map.regionmap.layers[].fields[]:`:: Mandatory. Each layer +| [[regionmap-fields]] `map.regionmap.layers[].fields[]:` + | Mandatory. Each layer can contain multiple fields to indicate what properties from the geojson -features you wish to expose. This <> shows how to define multiple -properties. Supported on {ece}. +features you wish to expose. Supported on {ece}. The following shows how to define multiple +properties: + +|=== -[[regionmap-field-description]]`map.regionmap.layers[].fields[].description:`:: -Mandatory. The human readable text that is shown under the Options tab when +[source,text] +-- +map.regionmap: + includeElasticMapsService: false + layers: + - name: "Departments of France" + url: "http://my.cors.enabled.server.org/france_departements.geojson" + attribution: "INRAP" + fields: + - name: "department" + description: "Full department name" + - name: "INSEE" + description: "INSEE numeric identifier" +-- + +[cols="2*<"] +|=== + +| [[regionmap-field-description]] `map.regionmap.layers[].fields[].description:` + | Mandatory. The human readable text that is shown under the Options tab when building the Region Map visualization. Supported on {ece}. -[[regionmap-field-name]]`map.regionmap.layers[].fields[].name:`:: Mandatory. +| [[regionmap-field-name]] `map.regionmap.layers[].fields[].name:` + | Mandatory. This value is used to do an inner-join between the document stored in -Elasticsearch and the geojson file. For example, if the field in the geojson is -called `Location` and has city names, there must be a field in Elasticsearch -that holds the same values that Kibana can then use to lookup for the geoshape +{es} and the geojson file. For example, if the field in the geojson is +called `Location` and has city names, there must be a field in {es} +that holds the same values that {kib} can then use to lookup for the geoshape data. Supported on {ece}. -[[regionmap-name]]`map.regionmap.layers[].name:`:: Mandatory. A description of +| [[regionmap-name]] `map.regionmap.layers[].name:` + | Mandatory. A description of the map being provided. Supported on {ece}. -[[regionmap-url]]`map.regionmap.layers[].url:`:: Mandatory. The location of the +| [[regionmap-url]] `map.regionmap.layers[].url:` + | Mandatory. The location of the geojson file as provided by a webserver. Supported on {ece}. -[[tilemap-settings]] `map.tilemap.options.attribution:`:: +| [[tilemap-settings]] `map.tilemap.options.attribution:` + | The map attribution string. Supported on {ece}. *Default: `"© [Elastic Maps Service](https://www.elastic.co/elastic-maps-service)"`* -The map attribution string. Supported on {ece}. -[[tilemap-max-zoom]]`map.tilemap.options.maxZoom:`:: *Default: 10* The maximum -zoom level. Supported on {ece}. +| [[tilemap-max-zoom]] `map.tilemap.options.maxZoom:` + | The maximum zoom level. Supported on {ece}. *Default: `10`* -[[tilemap-min-zoom]]`map.tilemap.options.minZoom:`:: *Default: 1* The minimum -zoom level. Supported on {ece}. +| [[tilemap-min-zoom]] `map.tilemap.options.minZoom:` + | The minimum zoom level. Supported on {ece}. *Default: `1`* -[[tilemap-subdomains]]`map.tilemap.options.subdomains:`:: An array of subdomains +| [[tilemap-subdomains]] `map.tilemap.options.subdomains:` + | An array of subdomains used by the tile service. Specify the position of the subdomain the URL with the token `{s}`. Supported on {ece}. -[[tilemap-url]]`map.tilemap.url:`:: The URL to the tileservice that Kibana uses +| [[tilemap-url]] `map.tilemap.url:` + | The URL to the tileservice that {kib} uses to display map tiles in tilemap visualizations. Supported on {ece}. By default, -Kibana reads this url from an external metadata service, but users can still +{kib} reads this URL from an external metadata service, but users can override this parameter to use their own Tile Map Service. For example: `"https://tiles.elastic.co/v2/default/{z}/{x}/{y}.png?elastic_tile_service_tos=agree&my_app_name=kibana"` -`newsfeed.enabled:` :: *Default: `true`* Controls whether to enable the newsfeed -system for the Kibana UI notification center. Set to `false` to disable the -newsfeed system. +| `newsfeed.enabled:` + | Controls whether to enable the newsfeed +system for the {kib} UI notification center. Set to `false` to disable the +newsfeed system. *Default: `true`* -`path.data:`:: *Default: `data`* The path where Kibana stores persistent data -not saved in Elasticsearch. +| `path.data:` + | The path where {kib} stores persistent data +not saved in {es}. *Default: `data`* -`pid.file:`:: Specifies the path where Kibana creates the process ID file. +| `pid.file:` + | Specifies the path where {kib} creates the process ID file. -`ops.interval:`:: *Default: 5000* Set the interval in milliseconds to sample -system and process performance metrics. The minimum value is 100. +| `ops.interval:` + | Set the interval in milliseconds to sample +system and process performance metrics. The minimum value is 100. *Default: `5000`* -`server.basePath:`:: Enables you to specify a path to mount Kibana at if you are -running behind a proxy. Use the `server.rewriteBasePath` setting to tell Kibana +| `server.basePath:` + | Enables you to specify a path to mount {kib} at if you are +running behind a proxy. Use the `server.rewriteBasePath` setting to tell {kib} if it should remove the basePath from requests it receives, and to prevent a deprecation warning at startup. This setting cannot end in a slash (`/`). -[[server-compression]]`server.compression.enabled:`:: *Default: `true`* Set to `false` to disable HTTP compression for all responses. +| [[server-compression]] `server.compression.enabled:` + | Set to `false` to disable HTTP compression for all responses. *Default: `true`* -`server.compression.referrerWhitelist:`:: *Default: none* Specifies an array of trusted hostnames, such as the Kibana host, or a reverse -proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request's `Referer` header. -This setting may not be used when `server.compression.enabled` is set to `false`. +| `server.compression.referrerWhitelist:` + | Specifies an array of trusted hostnames, such as the {kib} host, or a reverse +proxy sitting in front of it. This determines whether HTTP compression may be used for responses, based on the request `Referer` header. +This setting may not be used when `server.compression.enabled` is set to `false`. *Default: `none`* -`server.customResponseHeaders:`:: *Default: `{}`* Header names and values to - send on all responses to the client from the Kibana server. +| `server.customResponseHeaders:` + | Header names and values to +send on all responses to the client from the {kib} server. *Default: `{}`* -`server.host:`:: *Default: "localhost"* This setting specifies the host of the -back end server. To allow remote users to connect, set the value to the IP address or DNS name of the {kib} server. +| `server.host:` + | This setting specifies the host of the +back end server. To allow remote users to connect, set the value to the IP address or DNS name of the {kib} server. *Default: `"localhost"`* -`server.keepaliveTimeout:`:: *Default: "120000"* The number of milliseconds to wait for additional data before restarting -the `server.socketTimeout` counter. +| `server.keepaliveTimeout:` + | The number of milliseconds to wait for additional data before restarting +the `server.socketTimeout` counter. *Default: `"120000"`* -`server.maxPayloadBytes:`:: *Default: 1048576* The maximum payload size in bytes -for incoming server requests. +| `server.maxPayloadBytes:` + | The maximum payload size in bytes +for incoming server requests. *Default: `1048576`* -`server.name:`:: *Default: "your-hostname"* A human-readable display name that -identifies this Kibana instance. +| `server.name:` + | A human-readable display name that +identifies this {kib} instance. *Default: `"your-hostname"`* -`server.port:`:: *Default: 5601* Kibana is served by a back end server. This -setting specifies the port to use. +| `server.port:` + | {kib} is served by a back end server. This +setting specifies the port to use. *Default: `5601`* -`server.rewriteBasePath:`:: *Default: deprecated* Specifies whether Kibana should +| `server.rewriteBasePath:` + | Specifies whether {kib} should rewrite requests that are prefixed with `server.basePath` or require that they -are rewritten by your reverse proxy. In Kibana 6.3 and earlier, the default is -`false`. In Kibana 7.x, the setting is deprecated. In Kibana 8.0 and later, the -default is `true`. +are rewritten by your reverse proxy. In {kib} 6.3 and earlier, the default is +`false`. In {kib} 7.x, the setting is deprecated. In {kib} 8.0 and later, the +default is `true`. *Default: `deprecated`* -`server.socketTimeout:`:: *Default: "120000"* The number of milliseconds to wait before closing an -inactive socket. +| `server.socketTimeout:` + | The number of milliseconds to wait before closing an +inactive socket. *Default: `"120000"`* -`server.ssl.certificate:` and `server.ssl.key:`:: Paths to a PEM-encoded X.509 server certificate and its corresponding private key. These -are used by {kib} to establish trust when receiving inbound SSL/TLS connections from end users. -+ -NOTE: These settings cannot be used in conjunction with `server.ssl.keystore.path`. +| `server.ssl.certificate:` and `server.ssl.key:` + | Paths to a PEM-encoded X.509 server certificate and its corresponding private key. These +are used by {kib} to establish trust when receiving inbound SSL/TLS connections from users. + +|=== -`server.ssl.certificateAuthorities:`:: Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates which make up a +[NOTE] +============ +These settings cannot be used in conjunction with `server.ssl.keystore.path`. +============ + +[cols="2*<"] +|=== + +| `server.ssl.certificateAuthorities:` + | Paths to one or more PEM-encoded X.509 certificate authority (CA) certificates which make up a trusted certificate chain for {kib}. This chain is used by {kib} to establish trust when receiving inbound SSL/TLS connections from end users. If PKI authentication is enabled, this chain is also used by {kib} to verify client certificates from end users. + In addition to this setting, trusted certificates may be specified via `server.ssl.keystore.path` and/or `server.ssl.truststore.path`. -`server.ssl.cipherSuites:`:: *Default: ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA*. -Details on the format, and the valid options, are available via the +| `server.ssl.cipherSuites:` + | Details on the format, and the valid options, are available via the https://www.openssl.org/docs/man1.0.2/apps/ciphers.html#CIPHER-LIST-FORMAT[OpenSSL cipher list format documentation]. +*Default: `ECDHE-RSA-AES128-GCM-SHA256, ECDHE-ECDSA-AES128-GCM-SHA256, ECDHE-RSA-AES256-GCM-SHA384, ECDHE-ECDSA-AES256-GCM-SHA384, DHE-RSA-AES128-GCM-SHA256, ECDHE-RSA-AES128-SHA256, DHE-RSA-AES128-SHA256, ECDHE-RSA-AES256-SHA384, DHE-RSA-AES256-SHA384, ECDHE-RSA-AES256-SHA256, DHE-RSA-AES256-SHA256, HIGH,!aNULL, !eNULL, !EXPORT, !DES, !RC4, !MD5, !PSK, !SRP, !CAMELLIA`*. -`server.ssl.clientAuthentication:`:: *Default: `"none"`* Controls {kib}’s behavior in regard to requesting a certificate from client +| `server.ssl.clientAuthentication:` + | Controls the behavior in {kib} for requesting a certificate from client connections. Valid values are `"required"`, `"optional"`, and `"none"`. Using `"required"` will refuse to establish the connection unless a client presents a certificate, using `"optional"` will allow a client to present a certificate if it has one, and using `"none"` will -prevent a client from presenting a certificate. +prevent a client from presenting a certificate. *Default: `"none"`* -`server.ssl.enabled:`:: *Default: `false`* Enables SSL/TLS for inbound connections to {kib}. When set to `true`, a certificate and its +| `server.ssl.enabled:` + | Enables SSL/TLS for inbound connections to {kib}. When set to `true`, a certificate and its corresponding private key must be provided. These can be specified via `server.ssl.keystore.path` or the combination of -`server.ssl.certificate` and `server.ssl.key`. +`server.ssl.certificate` and `server.ssl.key`. *Default: `false`* -`server.ssl.keyPassphrase:`:: The password that will be used to decrypt the private key that is specified via `server.ssl.key`. This value +| `server.ssl.keyPassphrase:` + | The password that decrypts the private key that is specified via `server.ssl.key`. This value is optional, as the key may not be encrypted. -`server.ssl.keystore.path:`:: Path to a PKCS#12 keystore that contains an X.509 server certificate and its corresponding private key. If the +| `server.ssl.keystore.path:` + | Path to a PKCS#12 keystore that contains an X.509 server certificate and its corresponding private key. If the keystore contains any additional certificates, those will be used as a trusted certificate chain for {kib}. All of these are used by {kib} to establish trust when receiving inbound SSL/TLS connections from end users. The certificate chain is also used by {kib} to verify client certificates from end users when PKI authentication is enabled. + --- In addition to this setting, trusted certificates may be specified via `server.ssl.certificateAuthorities` and/or `server.ssl.truststore.path`. -NOTE: This setting cannot be used in conjunction with `server.ssl.certificate` or `server.ssl.key`. --- +|=== + +[NOTE] +============ +This setting cannot be used in conjunction with `server.ssl.certificate` or `server.ssl.key` +============ -`server.ssl.keystore.password:`:: The password that will be used to decrypt the keystore specified via `server.ssl.keystore.path`. If the +[cols="2*<"] +|=== + +| `server.ssl.keystore.password:` + | The password that will be used to decrypt the keystore specified via `server.ssl.keystore.path`. If the keystore has no password, leave this unset. If the keystore has an empty password, set this to `""`. -`server.ssl.truststore.path:`:: Path to a PKCS#12 trust store that contains one or more X.509 certificate authority (CA) certificates which +| `server.ssl.truststore.path:` + | Path to a PKCS#12 trust store that contains one or more X.509 certificate authority (CA) certificates which make up a trusted certificate chain for {kib}. This chain is used by {kib} to establish trust when receiving inbound SSL/TLS connections from end users. If PKI authentication is enabled, this chain is also used by {kib} to verify client certificates from end users. + In addition to this setting, trusted certificates may be specified via `server.ssl.certificateAuthorities` and/or `server.ssl.keystore.path`. -`server.ssl.truststore.password:`:: The password that will be used to decrypt the trust store specified via `server.ssl.truststore.path`. If +| `server.ssl.truststore.password:` + | The password that will be used to decrypt the trust store specified via `server.ssl.truststore.path`. If the trust store has no password, leave this unset. If the trust store has an empty password, set this to `""`. -`server.ssl.redirectHttpFromPort:`:: Kibana will bind to this port and redirect +| `server.ssl.redirectHttpFromPort:` + | {kib} binds to this port and redirects all http requests to https over the port configured as `server.port`. -`server.ssl.supportedProtocols:`:: *Default: TLSv1.1, TLSv1.2* An array of -supported protocols with versions. Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2` +| `server.ssl.supportedProtocols:` + | An array of supported protocols with versions. +Valid protocols: `TLSv1`, `TLSv1.1`, `TLSv1.2`. *Default: TLSv1.1, TLSv1.2* -`server.xsrf.whitelist:`:: It is not recommended to disable protections for +| `server.xsrf.whitelist:` + | It is not recommended to disable protections for arbitrary API endpoints. Instead, supply the `kbn-xsrf` header. The `server.xsrf.whitelist` setting requires the following format: -[source,text] +|=== +[source,text] ---- *Default: [ ]* An array of API endpoints which should be exempt from Cross-Site Request Forgery ("XSRF") protections. ---- -`status.allowAnonymous:`:: *Default: false* If authentication is enabled, -setting this to `true` enables unauthenticated users to access the Kibana -server status API and status page. +[cols="2*<"] +|=== + +| `status.allowAnonymous:` + | If authentication is enabled, +setting this to `true` enables unauthenticated users to access the {kib} +server status API and status page. *Default: `false`* -`telemetry.allowChangingOptInStatus`:: *Default: true*. If `true`, -users are able to change the telemetry setting at a later time in -<>. If `false`, +| `telemetry.allowChangingOptInStatus` + | When `true`, users are able to change the telemetry setting at a later time in +<>. When `false`, {kib} looks at the value of `telemetry.optIn` to determine whether to send telemetry data or not. `telemetry.allowChangingOptInStatus` and `telemetry.optIn` -cannot be `false` at the same time. +cannot be `false` at the same time. *Default: `true`*. -`telemetry.optIn`:: *Default: true* If `true`, telemetry data is sent to Elastic. - If `false`, collection of telemetry data is disabled. - To enable telemetry and prevent users from disabling it, - set `telemetry.allowChangingOptInStatus` to `false` and `telemetry.optIn` to `true`. +| `telemetry.optIn` + | When `true`, telemetry data is sent to Elastic. +When `false`, collection of telemetry data is disabled. +To enable telemetry and prevent users from disabling it, +set `telemetry.allowChangingOptInStatus` to `false` and `telemetry.optIn` to `true`. +*Default: `true`* -`telemetry.enabled`:: *Default: true* Reporting your cluster statistics helps +| `telemetry.enabled` + | Reporting your cluster statistics helps us improve your user experience. Your data is never shared with anyone. Set to `false` to disable telemetry capabilities entirely. You can alternatively opt -out through the *Advanced Settings* in {kib}. +out through *Advanced Settings*. *Default: `true`* + +| `vis_type_vega.enableExternalUrls:` + | Set this value to true to allow Vega to use any URL to access external data +sources and images. When false, Vega can only get data from {es}. *Default: `false`* -`vis_type_vega.enableExternalUrls:`:: *Default: false* Set this value to true to allow Vega to use any URL to access external data sources and images. If false, Vega can only get data from Elasticsearch. +| `xpack.license_management.enabled` + | Set this value to false to +disable the License Management UI. *Default: `true`* -`xpack.license_management.enabled`:: *Default: true* Set this value to false to -disable the License Management user interface. +| `xpack.rollup.enabled:` + | Set this value to false to disable the +Rollup UI. *Default: true* -`xpack.rollup.enabled:`:: *Default: true* Set this value to false to disable the -Rollup user interface. +| `i18n.locale` + | Set this value to change the {kib} interface language. +Valid locales are: `en`, `zh-CN`, `ja-JP`. *Default: `en`* -`i18n.locale`:: *Default: en* Set this value to change the Kibana interface language. Valid locales are: `en`, `zh-CN`, `ja-JP`. +|=== include::{docdir}/settings/alert-action-settings.asciidoc[] include::{docdir}/settings/apm-settings.asciidoc[] diff --git a/docs/user/alerting/action-types/pagerduty.asciidoc b/docs/user/alerting/action-types/pagerduty.asciidoc index abdcc7d1ba524..673b4f6263e18 100644 --- a/docs/user/alerting/action-types/pagerduty.asciidoc +++ b/docs/user/alerting/action-types/pagerduty.asciidoc @@ -92,7 +92,7 @@ section of the alert configuration and selecting *Add new*. * Alternatively, create a connector by navigating to *Management* from the {kib} navbar and selecting *Alerts and Actions*. Then, select the *Connectors* tab, click the *Create connector* button, and select the PagerDuty option. -. Configure the connector by giving it a name and optionally entering the API URL and Routing Key, or using the defaults. +. Configure the connector by giving it a name and entering the Integration Key, optionally entering a custom API URL. + See <> for how to obtain the endpoint and key information from PagerDuty and <> for more details. @@ -133,7 +133,7 @@ PagerDuty connectors have the following configuration properties: Name:: The name of the connector. The name is used to identify a connector in the management UI connector listing, or in the connector list when configuring an action. API URL:: An optional PagerDuty event URL. Defaults to `https://events.pagerduty.com/v2/enqueue`. If you are using the <> setting, make sure the hostname is whitelisted. -Routing Key:: A 32 character PagerDuty Integration Key for an integration on a service or on a global ruleset. +Integration Key:: A 32 character PagerDuty Integration Key for an integration on a service, also referred to as the routing key. [float] [[pagerduty-action-configuration]] diff --git a/docs/user/discover.asciidoc b/docs/user/discover.asciidoc index 2547b38a22616..7bac80237a26e 100644 --- a/docs/user/discover.asciidoc +++ b/docs/user/discover.asciidoc @@ -21,6 +21,7 @@ image::images/Discover-Start.png[Discover] [float] +[[select-pattern]] === Set up your index pattern The first thing to do in *Discover* is to select an <>, which diff --git a/docs/user/reporting/development/pdf-integration.asciidoc b/docs/user/reporting/development/pdf-integration.asciidoc index af5ba5be1636e..e9f32de41baab 100644 --- a/docs/user/reporting/development/pdf-integration.asciidoc +++ b/docs/user/reporting/development/pdf-integration.asciidoc @@ -63,3 +63,5 @@ If there are multiple visualizations, the `data-shared-items-count` attribute sh many Visualizations to look for. Reporting will look at every element with the `data-shared-item` attribute and use the corresponding `data-render-complete` attribute and `renderComplete` events to listen for rendering to complete. When rendering is complete for a visualization the `data-render-complete` attribute should be set to "true" and it should dispatch a custom DOM `renderComplete` event. + +If the reporting job uses multiple URLs, before looking for any of the `data-shared-item` or `data-shared-items-count` attributes, it waits for a `data-shared-page` attribute that specifies which page is being loaded. diff --git a/examples/ui_action_examples/public/index.ts b/examples/ui_action_examples/public/index.ts index 88a36d278e256..5b08192a1196e 100644 --- a/examples/ui_action_examples/public/index.ts +++ b/examples/ui_action_examples/public/index.ts @@ -18,9 +18,8 @@ */ import { UiActionExamplesPlugin } from './plugin'; -import { PluginInitializer } from '../../../src/core/public'; -export const plugin: PluginInitializer = () => new UiActionExamplesPlugin(); +export const plugin = () => new UiActionExamplesPlugin(); export { HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger'; export { ACTION_HELLO_WORLD } from './hello_world_action'; diff --git a/examples/ui_action_examples/public/plugin.ts b/examples/ui_action_examples/public/plugin.ts index c47746d4b3fd6..3a9f673261e33 100644 --- a/examples/ui_action_examples/public/plugin.ts +++ b/examples/ui_action_examples/public/plugin.ts @@ -17,15 +17,19 @@ * under the License. */ -import { Plugin, CoreSetup } from '../../../src/core/public'; -import { UiActionsSetup } from '../../../src/plugins/ui_actions/public'; +import { Plugin, CoreSetup, CoreStart } from '../../../src/core/public'; +import { UiActionsSetup, UiActionsStart } from '../../../src/plugins/ui_actions/public'; import { createHelloWorldAction, ACTION_HELLO_WORLD } from './hello_world_action'; import { helloWorldTrigger, HELLO_WORLD_TRIGGER_ID } from './hello_world_trigger'; -interface UiActionExamplesSetupDependencies { +export interface UiActionExamplesSetupDependencies { uiActions: UiActionsSetup; } +export interface UiActionExamplesStartDependencies { + uiActions: UiActionsStart; +} + declare module '../../../src/plugins/ui_actions/public' { export interface TriggerContextMapping { [HELLO_WORLD_TRIGGER_ID]: {}; @@ -37,8 +41,12 @@ declare module '../../../src/plugins/ui_actions/public' { } export class UiActionExamplesPlugin - implements Plugin { - public setup(core: CoreSetup, { uiActions }: UiActionExamplesSetupDependencies) { + implements + Plugin { + public setup( + core: CoreSetup, + { uiActions }: UiActionExamplesSetupDependencies + ) { uiActions.registerTrigger(helloWorldTrigger); const helloWorldAction = createHelloWorldAction(async () => ({ @@ -46,9 +54,10 @@ export class UiActionExamplesPlugin })); uiActions.registerAction(helloWorldAction); - uiActions.attachAction(helloWorldTrigger.id, helloWorldAction); + uiActions.addTriggerAction(helloWorldTrigger.id, helloWorldAction); } - public start() {} + public start(core: CoreStart, plugins: UiActionExamplesStartDependencies) {} + public stop() {} } diff --git a/examples/ui_actions_explorer/public/app.tsx b/examples/ui_actions_explorer/public/app.tsx index 462f5c3bf88ba..f08b8bb29bdd3 100644 --- a/examples/ui_actions_explorer/public/app.tsx +++ b/examples/ui_actions_explorer/public/app.tsx @@ -95,8 +95,7 @@ const ActionsExplorer = ({ uiActionsApi, openModal }: Props) => { ); }, }); - uiActionsApi.registerAction(dynamicAction); - uiActionsApi.attachAction(HELLO_WORLD_TRIGGER_ID, dynamicAction); + uiActionsApi.addTriggerAction(HELLO_WORLD_TRIGGER_ID, dynamicAction); setConfirmationText( `You've successfully added a new action: ${dynamicAction.getDisplayName( {} diff --git a/examples/ui_actions_explorer/public/plugin.tsx b/examples/ui_actions_explorer/public/plugin.tsx index f1895905a45e1..de86b51aee3a8 100644 --- a/examples/ui_actions_explorer/public/plugin.tsx +++ b/examples/ui_actions_explorer/public/plugin.tsx @@ -79,21 +79,21 @@ export class UiActionsExplorerPlugin implements Plugin (await startServices)[1].uiActions) ); - deps.uiActions.attachAction( + deps.uiActions.addTriggerAction( USER_TRIGGER, createEditUserAction(async () => (await startServices)[0].overlays.openModal) ); - deps.uiActions.attachAction(COUNTRY_TRIGGER, viewInMapsAction); - deps.uiActions.attachAction(COUNTRY_TRIGGER, lookUpWeatherAction); - deps.uiActions.attachAction(COUNTRY_TRIGGER, showcasePluggability); - deps.uiActions.attachAction(PHONE_TRIGGER, makePhoneCallAction); - deps.uiActions.attachAction(PHONE_TRIGGER, showcasePluggability); - deps.uiActions.attachAction(USER_TRIGGER, showcasePluggability); + deps.uiActions.addTriggerAction(COUNTRY_TRIGGER, viewInMapsAction); + deps.uiActions.addTriggerAction(COUNTRY_TRIGGER, lookUpWeatherAction); + deps.uiActions.addTriggerAction(COUNTRY_TRIGGER, showcasePluggability); + deps.uiActions.addTriggerAction(PHONE_TRIGGER, makePhoneCallAction); + deps.uiActions.addTriggerAction(PHONE_TRIGGER, showcasePluggability); + deps.uiActions.addTriggerAction(USER_TRIGGER, showcasePluggability); core.application.register({ id: 'uiActionsExplorer', diff --git a/package.json b/package.json index 0ad304fdf2f69..1f0658bd2a138 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "@babel/core": "^7.9.0", "@babel/register": "^7.9.0", "@elastic/apm-rum": "^5.1.1", - "@elastic/charts": "18.4.2", + "@elastic/charts": "19.1.2", "@elastic/datemath": "5.0.3", "@elastic/ems-client": "7.8.0", "@elastic/eui": "22.3.0", @@ -146,6 +146,7 @@ "@types/tar": "^4.0.3", "JSONStream": "1.3.5", "abortcontroller-polyfill": "^1.4.0", + "accept": "3.0.2", "angular": "^1.7.9", "angular-aria": "^1.7.9", "angular-elastic": "^2.5.1", @@ -310,6 +311,7 @@ "@percy/agent": "^0.26.0", "@testing-library/react": "^9.3.2", "@testing-library/react-hooks": "^3.2.1", + "@types/accept": "3.1.1", "@types/angular": "^1.6.56", "@types/angular-mocks": "^1.7.0", "@types/babel__core": "^7.1.2", @@ -400,7 +402,7 @@ "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "babel-plugin-istanbul": "^6.0.0", - "backport": "5.1.3", + "backport": "5.4.1", "chai": "3.5.0", "chance": "1.0.18", "cheerio": "0.22.0", diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index b3e5a8c518682..b7c9a63897bf9 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -14,6 +14,7 @@ "@kbn/babel-preset": "1.0.0", "@kbn/dev-utils": "1.0.0", "@kbn/ui-shared-deps": "1.0.0", + "@types/compression-webpack-plugin": "^2.0.1", "@types/estree": "^0.0.44", "@types/loader-utils": "^1.1.3", "@types/watchpack": "^1.1.5", @@ -23,6 +24,7 @@ "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", "clean-webpack-plugin": "^3.0.0", + "compression-webpack-plugin": "^3.1.0", "cpy": "^8.0.0", "css-loader": "^3.4.2", "del": "^5.1.0", diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index ad743933e1171..248b0b7cf4c97 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -19,6 +19,7 @@ import Path from 'path'; import Fs from 'fs'; +import Zlib from 'zlib'; import { inspect } from 'util'; import cpy from 'cpy'; @@ -124,17 +125,12 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { ); assert('produce zero unexpected states', otherStates.length === 0, otherStates); - expect( - Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/foo/target/public/foo.plugin.js'), 'utf8') - ).toMatchSnapshot('foo bundle'); - - expect( - Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/foo/target/public/1.plugin.js'), 'utf8') - ).toMatchSnapshot('1 async bundle'); - - expect( - Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/bar/target/public/bar.plugin.js'), 'utf8') - ).toMatchSnapshot('bar bundle'); + expectFileMatchesSnapshotWithCompression('plugins/foo/target/public/foo.plugin.js', 'foo bundle'); + expectFileMatchesSnapshotWithCompression( + 'plugins/foo/target/public/1.plugin.js', + '1 async bundle' + ); + expectFileMatchesSnapshotWithCompression('plugins/bar/target/public/bar.plugin.js', 'bar bundle'); const foo = config.bundles.find(b => b.id === 'foo')!; expect(foo).toBeTruthy(); @@ -203,3 +199,24 @@ it('uses cache on second run and exist cleanly', async () => { ] `); }); + +/** + * Verifies that the file matches the expected output and has matching compressed variants. + */ +const expectFileMatchesSnapshotWithCompression = (filePath: string, snapshotLabel: string) => { + const raw = Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, filePath), 'utf8'); + expect(raw).toMatchSnapshot(snapshotLabel); + + // Verify the brotli variant matches + expect( + // @ts-ignore @types/node is missing the brotli functions + Zlib.brotliDecompressSync( + Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, `${filePath}.br`)) + ).toString() + ).toEqual(raw); + + // Verify the gzip variant matches + expect( + Zlib.gunzipSync(Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, `${filePath}.gz`))).toString() + ).toEqual(raw); +}; diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index cc3fa8c2720de..95e826e7620aa 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -28,6 +28,7 @@ import TerserPlugin from 'terser-webpack-plugin'; import webpackMerge from 'webpack-merge'; // @ts-ignore import { CleanWebpackPlugin } from 'clean-webpack-plugin'; +import CompressionPlugin from 'compression-webpack-plugin'; import * as UiSharedDeps from '@kbn/ui-shared-deps'; import { Bundle, WorkerConfig, parseDirPath, DisallowedSyntaxPlugin } from '../common'; @@ -319,6 +320,16 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { IS_KIBANA_DISTRIBUTABLE: `"true"`, }, }), + new CompressionPlugin({ + algorithm: 'brotliCompress', + filename: '[path].br', + test: /\.(js|css)$/, + }), + new CompressionPlugin({ + algorithm: 'gzip', + filename: '[path].gz', + test: /\.(js|css)$/, + }), ], optimization: { diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index a60e2b0449d95..a2248f1ae655e 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -9,11 +9,12 @@ "kbn:watch": "node scripts/build --watch" }, "dependencies": { - "@elastic/charts": "18.4.2", + "@elastic/charts": "19.1.2", "@elastic/eui": "22.3.0", "@kbn/i18n": "1.0.0", "abortcontroller-polyfill": "^1.4.0", "angular": "^1.7.9", + "compression-webpack-plugin": "^3.1.0", "core-js": "^3.6.4", "custom-event-polyfill": "^0.3.0", "elasticsearch-browser": "^16.7.0", diff --git a/packages/kbn-ui-shared-deps/webpack.config.js b/packages/kbn-ui-shared-deps/webpack.config.js index bf63c57765859..ca913d0f16417 100644 --- a/packages/kbn-ui-shared-deps/webpack.config.js +++ b/packages/kbn-ui-shared-deps/webpack.config.js @@ -20,6 +20,7 @@ const Path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const CompressionPlugin = require('compression-webpack-plugin'); const { REPO_ROOT } = require('@kbn/dev-utils'); const webpack = require('webpack'); @@ -117,5 +118,19 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({ new webpack.DefinePlugin({ 'process.env.NODE_ENV': dev ? '"development"' : '"production"', }), + ...(dev + ? [] + : [ + new CompressionPlugin({ + algorithm: 'brotliCompress', + filename: '[path].br', + test: /\.(js|css)$/, + }), + new CompressionPlugin({ + algorithm: 'gzip', + filename: '[path].gz', + test: /\.(js|css)$/, + }), + ]), ], }); diff --git a/renovate.json5 b/renovate.json5 index c0ddcaf4f23c8..61b2485ecf44b 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -398,6 +398,8 @@ '@types/good-squeeze', 'inert', '@types/inert', + 'accept', + '@types/accept', ], }, { diff --git a/src/core/public/application/__snapshots__/application_service.test.ts.snap b/src/core/public/application/__snapshots__/application_service.test.ts.snap index 376b320b64ea9..c085fb028cd5a 100644 --- a/src/core/public/application/__snapshots__/application_service.test.ts.snap +++ b/src/core/public/application/__snapshots__/application_service.test.ts.snap @@ -80,5 +80,6 @@ exports[`#start() getComponent returns renderable JSX tree 1`] = ` } mounters={Map {}} setAppLeaveHandler={[Function]} + setIsMounting={[Function]} /> `; diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index e29837aecb125..04ff844ffc150 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -20,7 +20,7 @@ import { createElement } from 'react'; import { BehaviorSubject, Subject } from 'rxjs'; import { bufferCount, take, takeUntil } from 'rxjs/operators'; -import { shallow } from 'enzyme'; +import { shallow, mount } from 'enzyme'; import { injectedMetadataServiceMock } from '../injected_metadata/injected_metadata_service.mock'; import { contextServiceMock } from '../context/context_service.mock'; @@ -30,6 +30,7 @@ import { MockCapabilitiesService, MockHistory } from './application_service.test import { MockLifecycle } from './test_types'; import { ApplicationService } from './application_service'; import { App, AppNavLinkStatus, AppStatus, AppUpdater, LegacyApp } from './types'; +import { act } from 'react-dom/test-utils'; const createApp = (props: Partial): App => { return { @@ -452,9 +453,9 @@ describe('#setup()', () => { const container = setupDeps.context.createContextContainer.mock.results[0].value; const pluginId = Symbol(); - const mount = () => () => undefined; - registerMountContext(pluginId, 'test' as any, mount); - expect(container.registerContext).toHaveBeenCalledWith(pluginId, 'test', mount); + const appMount = () => () => undefined; + registerMountContext(pluginId, 'test' as any, appMount); + expect(container.registerContext).toHaveBeenCalledWith(pluginId, 'test', appMount); }); }); @@ -809,6 +810,74 @@ describe('#start()', () => { `); }); + it('updates httpLoadingCount$ while mounting', async () => { + // Use a memory history so that mounting the component will work + const { createMemoryHistory } = jest.requireActual('history'); + const history = createMemoryHistory(); + setupDeps.history = history; + + const flushPromises = () => new Promise(resolve => setImmediate(resolve)); + // Create an app and a promise that allows us to control when the app completes mounting + const createWaitingApp = (props: Partial): [App, () => void] => { + let finishMount: () => void; + const mountPromise = new Promise(resolve => (finishMount = resolve)); + const app = { + id: 'some-id', + title: 'some-title', + mount: async () => { + await mountPromise; + return () => undefined; + }, + ...props, + }; + + return [app, finishMount!]; + }; + + // Create some dummy applications + const { register } = service.setup(setupDeps); + const [alphaApp, finishAlphaMount] = createWaitingApp({ id: 'alpha' }); + const [betaApp, finishBetaMount] = createWaitingApp({ id: 'beta' }); + register(Symbol(), alphaApp); + register(Symbol(), betaApp); + + const { navigateToApp, getComponent } = await service.start(startDeps); + const httpLoadingCount$ = startDeps.http.addLoadingCountSource.mock.calls[0][0]; + const stop$ = new Subject(); + const currentLoadingCount$ = new BehaviorSubject(0); + httpLoadingCount$.pipe(takeUntil(stop$)).subscribe(currentLoadingCount$); + const loadingPromise = httpLoadingCount$.pipe(bufferCount(5), takeUntil(stop$)).toPromise(); + mount(getComponent()!); + + await act(() => navigateToApp('alpha')); + expect(currentLoadingCount$.value).toEqual(1); + await act(async () => { + finishAlphaMount(); + await flushPromises(); + }); + expect(currentLoadingCount$.value).toEqual(0); + + await act(() => navigateToApp('beta')); + expect(currentLoadingCount$.value).toEqual(1); + await act(async () => { + finishBetaMount(); + await flushPromises(); + }); + expect(currentLoadingCount$.value).toEqual(0); + + stop$.next(); + const loadingCounts = await loadingPromise; + expect(loadingCounts).toMatchInlineSnapshot(` + Array [ + 0, + 1, + 0, + 1, + 0, + ] + `); + }); + it('sets window.location.href when navigating to legacy apps', async () => { setupDeps.http = httpServiceMock.createSetupContract({ basePath: '/test' }); setupDeps.injectedMetadata.getLegacyMode.mockReturnValue(true); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index bafa1932e5e92..0dd77072e9eaf 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -238,6 +238,9 @@ export class ApplicationService { throw new Error('ApplicationService#setup() must be invoked before start.'); } + const httpLoadingCount$ = new BehaviorSubject(0); + http.addLoadingCountSource(httpLoadingCount$); + this.registrationClosed = true; window.addEventListener('beforeunload', this.onBeforeUnload); @@ -303,6 +306,7 @@ export class ApplicationService { mounters={availableMounters} appStatuses$={applicationStatuses$} setAppLeaveHandler={this.setAppLeaveHandler} + setIsMounting={isMounting => httpLoadingCount$.next(isMounting ? 1 : 0)} /> ); }, diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx index 2f26bc1409104..915c58b28ad6d 100644 --- a/src/core/public/application/integration_tests/router.test.tsx +++ b/src/core/public/application/integration_tests/router.test.tsx @@ -40,7 +40,7 @@ describe('AppContainer', () => { }; const mockMountersToMounters = () => new Map([...mounters].map(([appId, { mounter }]) => [appId, mounter])); - const setAppLeaveHandlerMock = () => undefined; + const noop = () => undefined; const mountersToAppStatus$ = () => { return new BehaviorSubject( @@ -86,7 +86,8 @@ describe('AppContainer', () => { history={globalHistory} mounters={mockMountersToMounters()} appStatuses$={appStatuses$} - setAppLeaveHandler={setAppLeaveHandlerMock} + setAppLeaveHandler={noop} + setIsMounting={noop} /> ); }); @@ -98,7 +99,7 @@ describe('AppContainer', () => { expect(app1.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /app/app1 html: App 1
" @@ -110,7 +111,7 @@ describe('AppContainer', () => { expect(app1Unmount).toHaveBeenCalled(); expect(app2.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /app/app2 html:
App 2
" @@ -124,7 +125,7 @@ describe('AppContainer', () => { expect(standardApp.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /app/app1 html: App 1
" @@ -136,7 +137,7 @@ describe('AppContainer', () => { expect(standardAppUnmount).toHaveBeenCalled(); expect(chromelessApp.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /chromeless-a/path html:
Chromeless A
" @@ -148,7 +149,7 @@ describe('AppContainer', () => { expect(chromelessAppUnmount).toHaveBeenCalled(); expect(standardApp.mounter.mount).toHaveBeenCalledTimes(2); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /app/app1 html: App 1
" @@ -162,7 +163,7 @@ describe('AppContainer', () => { expect(chromelessAppA.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /chromeless-a/path html:
Chromeless A
" @@ -174,7 +175,7 @@ describe('AppContainer', () => { expect(chromelessAppAUnmount).toHaveBeenCalled(); expect(chromelessAppB.mounter.mount).toHaveBeenCalled(); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /chromeless-b/path html:
Chromeless B
" @@ -186,7 +187,7 @@ describe('AppContainer', () => { expect(chromelessAppBUnmount).toHaveBeenCalled(); expect(chromelessAppA.mounter.mount).toHaveBeenCalledTimes(2); expect(dom?.html()).toMatchInlineSnapshot(` - "
+ "
basename: /chromeless-a/path html:
Chromeless A
" @@ -214,7 +215,8 @@ describe('AppContainer', () => { history={globalHistory} mounters={mockMountersToMounters()} appStatuses$={mountersToAppStatus$()} - setAppLeaveHandler={setAppLeaveHandlerMock} + setAppLeaveHandler={noop} + setIsMounting={noop} /> ); @@ -245,7 +247,8 @@ describe('AppContainer', () => { history={globalHistory} mounters={mockMountersToMounters()} appStatuses$={mountersToAppStatus$()} - setAppLeaveHandler={setAppLeaveHandlerMock} + setAppLeaveHandler={noop} + setIsMounting={noop} /> ); @@ -286,7 +289,8 @@ describe('AppContainer', () => { history={globalHistory} mounters={mockMountersToMounters()} appStatuses$={mountersToAppStatus$()} - setAppLeaveHandler={setAppLeaveHandlerMock} + setAppLeaveHandler={noop} + setIsMounting={noop} /> ); diff --git a/src/core/public/application/integration_tests/utils.tsx b/src/core/public/application/integration_tests/utils.tsx index 9092177da5ad4..fa04b56f83ba1 100644 --- a/src/core/public/application/integration_tests/utils.tsx +++ b/src/core/public/application/integration_tests/utils.tsx @@ -18,6 +18,7 @@ */ import React, { ReactElement } from 'react'; +import { act } from 'react-dom/test-utils'; import { mount } from 'enzyme'; import { I18nProvider } from '@kbn/i18n/react'; @@ -34,7 +35,9 @@ export const createRenderer = (element: ReactElement | null): Renderer => { return () => new Promise(async resolve => { if (dom) { - dom.update(); + await act(async () => { + dom.update(); + }); } setImmediate(() => resolve(dom)); // flushes any pending promises }); diff --git a/src/core/public/application/ui/app_container.scss b/src/core/public/application/ui/app_container.scss new file mode 100644 index 0000000000000..4f8fec10a97e1 --- /dev/null +++ b/src/core/public/application/ui/app_container.scss @@ -0,0 +1,25 @@ +.appContainer__loading { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: $euiZLevel1; + animation-name: appContainerFadeIn; + animation-iteration-count: 1; + animation-timing-function: ease-in; + animation-duration: 2s; +} + +@keyframes appContainerFadeIn { + 0% { + opacity: 0; + } + + 50% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} diff --git a/src/core/public/application/ui/app_container.test.tsx b/src/core/public/application/ui/app_container.test.tsx index c538227e8f098..2ee71a5bde7dc 100644 --- a/src/core/public/application/ui/app_container.test.tsx +++ b/src/core/public/application/ui/app_container.test.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mount } from 'enzyme'; import { AppContainer } from './app_container'; @@ -28,6 +29,12 @@ import { ScopedHistory } from '../scoped_history'; describe('AppContainer', () => { const appId = 'someApp'; const setAppLeaveHandler = jest.fn(); + const setIsMounting = jest.fn(); + + beforeEach(() => { + setAppLeaveHandler.mockClear(); + setIsMounting.mockClear(); + }); const flushPromises = async () => { await new Promise(async resolve => { @@ -67,6 +74,7 @@ describe('AppContainer', () => { appStatus={AppStatus.inaccessible} mounter={mounter} setAppLeaveHandler={setAppLeaveHandler} + setIsMounting={setIsMounting} createScopedHistory={(appPath: string) => // Create a history using the appPath as the current location new ScopedHistory(createMemoryHistory({ initialEntries: [appPath] }), appPath) @@ -86,10 +94,86 @@ describe('AppContainer', () => { expect(wrapper.text()).toEqual(''); - resolvePromise(); - await flushPromises(); - wrapper.update(); + await act(async () => { + resolvePromise(); + await flushPromises(); + wrapper.update(); + }); expect(wrapper.text()).toContain('some-content'); }); + + it('should call setIsMounting while mounting', async () => { + const [waitPromise, resolvePromise] = createResolver(); + const mounter = createMounter(waitPromise); + + const wrapper = mount( + + // Create a history using the appPath as the current location + new ScopedHistory(createMemoryHistory({ initialEntries: [appPath] }), appPath) + } + /> + ); + + expect(setIsMounting).toHaveBeenCalledTimes(1); + expect(setIsMounting).toHaveBeenLastCalledWith(true); + + await act(async () => { + resolvePromise(); + await flushPromises(); + wrapper.update(); + }); + + expect(setIsMounting).toHaveBeenCalledTimes(2); + expect(setIsMounting).toHaveBeenLastCalledWith(false); + }); + + it('should call setIsMounting(false) if mounting throws', async () => { + const [waitPromise, resolvePromise] = createResolver(); + const mounter = { + appBasePath: '/base-path', + appRoute: '/some-route', + unmountBeforeMounting: false, + mount: async ({ element }: AppMountParameters) => { + await waitPromise; + throw new Error(`Mounting failed!`); + }, + }; + + const wrapper = mount( + + // Create a history using the appPath as the current location + new ScopedHistory(createMemoryHistory({ initialEntries: [appPath] }), appPath) + } + /> + ); + + expect(setIsMounting).toHaveBeenCalledTimes(1); + expect(setIsMounting).toHaveBeenLastCalledWith(true); + + // await expect( + await act(async () => { + resolvePromise(); + await flushPromises(); + wrapper.update(); + }); + // ).rejects.toThrow(); + + expect(setIsMounting).toHaveBeenCalledTimes(2); + expect(setIsMounting).toHaveBeenLastCalledWith(false); + }); }); diff --git a/src/core/public/application/ui/app_container.tsx b/src/core/public/application/ui/app_container.tsx index e12a0f2cf2fcd..aad7e6dcf270a 100644 --- a/src/core/public/application/ui/app_container.tsx +++ b/src/core/public/application/ui/app_container.tsx @@ -26,9 +26,11 @@ import React, { MutableRefObject, } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; import { AppLeaveHandler, AppStatus, AppUnmount, Mounter } from '../types'; import { AppNotFound } from './app_not_found_screen'; import { ScopedHistory } from '../scoped_history'; +import './app_container.scss'; interface Props { /** Path application is mounted on without the global basePath */ @@ -38,6 +40,7 @@ interface Props { appStatus: AppStatus; setAppLeaveHandler: (appId: string, handler: AppLeaveHandler) => void; createScopedHistory: (appUrl: string) => ScopedHistory; + setIsMounting: (isMounting: boolean) => void; } export const AppContainer: FunctionComponent = ({ @@ -47,7 +50,9 @@ export const AppContainer: FunctionComponent = ({ setAppLeaveHandler, createScopedHistory, appStatus, + setIsMounting, }: Props) => { + const [showSpinner, setShowSpinner] = useState(true); const [appNotFound, setAppNotFound] = useState(false); const elementRef = useRef(null); const unmountRef: MutableRefObject = useRef(null); @@ -65,28 +70,42 @@ export const AppContainer: FunctionComponent = ({ } setAppNotFound(false); + setIsMounting(true); if (mounter.unmountBeforeMounting) { unmount(); } const mount = async () => { - unmountRef.current = - (await mounter.mount({ - appBasePath: mounter.appBasePath, - history: createScopedHistory(appPath), - element: elementRef.current!, - onAppLeave: handler => setAppLeaveHandler(appId, handler), - })) || null; + setShowSpinner(true); + try { + unmountRef.current = + (await mounter.mount({ + appBasePath: mounter.appBasePath, + history: createScopedHistory(appPath), + element: elementRef.current!, + onAppLeave: handler => setAppLeaveHandler(appId, handler), + })) || null; + } catch (e) { + // TODO: add error UI + } finally { + setShowSpinner(false); + setIsMounting(false); + } }; mount(); return unmount; - }, [appId, appStatus, mounter, createScopedHistory, setAppLeaveHandler, appPath]); + }, [appId, appStatus, mounter, createScopedHistory, setAppLeaveHandler, appPath, setIsMounting]); return ( {appNotFound && } + {showSpinner && ( +
+ +
+ )}
); diff --git a/src/core/public/application/ui/app_router.tsx b/src/core/public/application/ui/app_router.tsx index 4c135c5769067..ea7c5c9308fe2 100644 --- a/src/core/public/application/ui/app_router.tsx +++ b/src/core/public/application/ui/app_router.tsx @@ -32,6 +32,7 @@ interface Props { history: History; appStatuses$: Observable>; setAppLeaveHandler: (appId: string, handler: AppLeaveHandler) => void; + setIsMounting: (isMounting: boolean) => void; } interface Params { @@ -43,6 +44,7 @@ export const AppRouter: FunctionComponent = ({ mounters, setAppLeaveHandler, appStatuses$, + setIsMounting, }) => { const appStatuses = useObservable(appStatuses$, new Map()); const createScopedHistory = useMemo( @@ -67,7 +69,7 @@ export const AppRouter: FunctionComponent = ({ appPath={url} appStatus={appStatuses.get(appId) ?? AppStatus.inaccessible} createScopedHistory={createScopedHistory} - {...{ appId, mounter, setAppLeaveHandler }} + {...{ appId, mounter, setAppLeaveHandler, setIsMounting }} /> )} />, @@ -92,7 +94,7 @@ export const AppRouter: FunctionComponent = ({ appId={id} appStatus={appStatuses.get(id) ?? AppStatus.inaccessible} createScopedHistory={createScopedHistory} - {...{ mounter, setAppLeaveHandler }} + {...{ mounter, setAppLeaveHandler, setIsMounting }} /> ); }} diff --git a/src/core/public/overlays/flyout/flyout_service.tsx b/src/core/public/overlays/flyout/flyout_service.tsx index b609b2ce1d741..444430175d4f2 100644 --- a/src/core/public/overlays/flyout/flyout_service.tsx +++ b/src/core/public/overlays/flyout/flyout_service.tsx @@ -91,6 +91,7 @@ export interface OverlayFlyoutStart { export interface OverlayFlyoutOpenOptions { className?: string; closeButtonAriaLabel?: string; + ownFocus?: boolean; 'data-test-subj'?: string; } diff --git a/src/core/server/elasticsearch/elasticsearch_service.mock.ts b/src/core/server/elasticsearch/elasticsearch_service.mock.ts index da8846f6dddbb..a7d78b56ff3fd 100644 --- a/src/core/server/elasticsearch/elasticsearch_service.mock.ts +++ b/src/core/server/elasticsearch/elasticsearch_service.mock.ts @@ -18,6 +18,7 @@ */ import { BehaviorSubject } from 'rxjs'; +import { Client } from 'elasticsearch'; import { IClusterClient, ICustomClusterClient } from './cluster_client'; import { IScopedClusterClient } from './scoped_cluster_client'; import { ElasticsearchConfig } from './elasticsearch_config'; @@ -130,6 +131,55 @@ const createMock = () => { return mocked; }; +const createElasticsearchClientMock = () => { + const mocked: jest.Mocked = { + cat: {} as any, + cluster: {} as any, + indices: {} as any, + ingest: {} as any, + nodes: {} as any, + snapshot: {} as any, + tasks: {} as any, + bulk: jest.fn(), + clearScroll: jest.fn(), + count: jest.fn(), + create: jest.fn(), + delete: jest.fn(), + deleteByQuery: jest.fn(), + deleteScript: jest.fn(), + deleteTemplate: jest.fn(), + exists: jest.fn(), + explain: jest.fn(), + fieldStats: jest.fn(), + get: jest.fn(), + getScript: jest.fn(), + getSource: jest.fn(), + getTemplate: jest.fn(), + index: jest.fn(), + info: jest.fn(), + mget: jest.fn(), + msearch: jest.fn(), + msearchTemplate: jest.fn(), + mtermvectors: jest.fn(), + ping: jest.fn(), + putScript: jest.fn(), + putTemplate: jest.fn(), + reindex: jest.fn(), + reindexRethrottle: jest.fn(), + renderSearchTemplate: jest.fn(), + scroll: jest.fn(), + search: jest.fn(), + searchShards: jest.fn(), + searchTemplate: jest.fn(), + suggest: jest.fn(), + termvectors: jest.fn(), + update: jest.fn(), + updateByQuery: jest.fn(), + close: jest.fn(), + }; + return mocked; +}; + export const elasticsearchServiceMock = { create: createMock, createInternalSetup: createInternalSetupContractMock, @@ -138,4 +188,5 @@ export const elasticsearchServiceMock = { createClusterClient: createClusterClientMock, createCustomClusterClient: createCustomClusterClientMock, createScopedClusterClient: createScopedClusterClientMock, + createElasticsearchClient: createElasticsearchClientMock, }; diff --git a/src/core/server/http/integration_tests/core_service.test.mocks.ts b/src/core/server/http/integration_tests/core_service.test.mocks.ts index 6fa3357168027..b3adda8dd22d1 100644 --- a/src/core/server/http/integration_tests/core_service.test.mocks.ts +++ b/src/core/server/http/integration_tests/core_service.test.mocks.ts @@ -24,3 +24,14 @@ jest.doMock('../../elasticsearch/scoped_cluster_client', () => ({ return elasticsearchServiceMock.createScopedClusterClient(); }), })); + +jest.doMock('elasticsearch', () => { + const realES = jest.requireActual('elasticsearch'); + return { + ...realES, + // eslint-disable-next-line object-shorthand + Client: function() { + return elasticsearchServiceMock.createElasticsearchClient(); + }, + }; +}); diff --git a/src/core/server/http/integration_tests/core_services.test.ts b/src/core/server/http/integration_tests/core_services.test.ts index 7b1630a7de0be..5726486a0930a 100644 --- a/src/core/server/http/integration_tests/core_services.test.ts +++ b/src/core/server/http/integration_tests/core_services.test.ts @@ -43,7 +43,7 @@ describe('http service', () => { describe('auth', () => { let root: ReturnType; beforeEach(async () => { - root = kbnTestServer.createRoot({ migrations: { skip: true } }); + root = kbnTestServer.createRoot(); }, 30000); afterEach(async () => { @@ -192,7 +192,7 @@ describe('http service', () => { let root: ReturnType; beforeEach(async () => { - root = kbnTestServer.createRoot({ migrations: { skip: true } }); + root = kbnTestServer.createRoot(); }, 30000); afterEach(async () => { @@ -326,7 +326,7 @@ describe('http service', () => { describe('#basePath()', () => { let root: ReturnType; beforeEach(async () => { - root = kbnTestServer.createRoot({ migrations: { skip: true } }); + root = kbnTestServer.createRoot(); }, 30000); afterEach(async () => await root.shutdown()); @@ -355,7 +355,7 @@ describe('http service', () => { describe('elasticsearch', () => { let root: ReturnType; beforeEach(async () => { - root = kbnTestServer.createRoot({ migrations: { skip: true } }); + root = kbnTestServer.createRoot(); }, 30000); afterEach(async () => { diff --git a/src/dev/renovate/package_groups.ts b/src/dev/renovate/package_groups.ts index 1bc65fd149f47..9f5aa8556ac21 100644 --- a/src/dev/renovate/package_groups.ts +++ b/src/dev/renovate/package_groups.ts @@ -159,7 +159,17 @@ export const RENOVATE_PACKAGE_GROUPS: PackageGroup[] = [ { name: 'hapi', packageWords: ['hapi'], - packageNames: ['hapi', 'joi', 'boom', 'hoek', 'h2o2', '@elastic/good', 'good-squeeze', 'inert'], + packageNames: [ + 'hapi', + 'joi', + 'boom', + 'hoek', + 'h2o2', + '@elastic/good', + 'good-squeeze', + 'inert', + 'accept', + ], }, { diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 4dc930dae3e25..0e91f0a214a45 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -18,12 +18,13 @@ */ export const storybookAliases = { + advanced_ui_actions: 'x-pack/plugins/advanced_ui_actions/scripts/storybook.js', apm: 'x-pack/plugins/apm/scripts/storybook.js', canvas: 'x-pack/legacy/plugins/canvas/scripts/storybook_new.js', codeeditor: 'src/plugins/kibana_react/public/code_editor/scripts/storybook.ts', + dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/scripts/storybook.js', drilldowns: 'x-pack/plugins/drilldowns/scripts/storybook.js', embeddable: 'src/plugins/embeddable/scripts/storybook.js', infra: 'x-pack/legacy/plugins/infra/scripts/storybook.js', siem: 'x-pack/plugins/siem/scripts/storybook.js', - ui_actions: 'x-pack/plugins/advanced_ui_actions/scripts/storybook.js', }; diff --git a/src/legacy/core_plugins/interpreter/README.md b/src/legacy/core_plugins/interpreter/README.md deleted file mode 100644 index 6d90ce2d5e2eb..0000000000000 --- a/src/legacy/core_plugins/interpreter/README.md +++ /dev/null @@ -1,2 +0,0 @@ -Interpreter legacy plugin has been migrated to the New Platform. Use -`expressions` New Platform plugin instead. diff --git a/src/legacy/core_plugins/interpreter/index.ts b/src/legacy/core_plugins/interpreter/index.ts deleted file mode 100644 index 9427a2f8a2d0f..0000000000000 --- a/src/legacy/core_plugins/interpreter/index.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { resolve } from 'path'; -import { Legacy } from '../../../../kibana'; -import { init } from './init'; - -// eslint-disable-next-line -export default function InterpreterPlugin(kibana: any) { - const config: Legacy.PluginSpecOptions = { - id: 'interpreter', - require: ['kibana', 'elasticsearch'], - publicDir: resolve(__dirname, 'public'), - uiExports: { - injectDefaultVars: server => ({ - serverBasePath: server.config().get('server.basePath'), - }), - }, - config: (Joi: any) => { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - init, - }; - - return new kibana.Plugin(config); -} diff --git a/src/legacy/core_plugins/interpreter/init.ts b/src/legacy/core_plugins/interpreter/init.ts deleted file mode 100644 index 46da1539afadb..0000000000000 --- a/src/legacy/core_plugins/interpreter/init.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* eslint-disable max-classes-per-file */ - -// @ts-ignore -import { register, registryFactory, Registry, Fn } from '@kbn/interpreter/common'; - -import { Legacy } from '../../../../kibana'; - -export async function init(server: Legacy.Server /* options */) { - server.injectUiAppVars('canvas', () => { - const config = server.config(); - const basePath = config.get('server.basePath'); - const reportingBrowserType = (() => { - const configKey = 'xpack.reporting.capture.browser.type'; - if (!config.has(configKey)) { - return null; - } - return config.get(configKey); - })(); - - return { - kbnIndex: config.get('kibana.index'), - serverFunctions: (server.newPlatform.setup.plugins.expressions as any).__LEGACY - .registries() - .serverFunctions.toArray(), - basePath, - reportingBrowserType, - }; - }); - - // Expose server.plugins.interpreter.register(specs) and - // server.plugins.interpreter.registries() (a getter). - server.expose((server.newPlatform.setup.plugins.expressions as any).__LEGACY); -} diff --git a/src/legacy/core_plugins/interpreter/package.json b/src/legacy/core_plugins/interpreter/package.json deleted file mode 100644 index 3265dadd7fbfc..0000000000000 --- a/src/legacy/core_plugins/interpreter/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "interpreter", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/interpreter/public/canvas/load_legacy_server_function_wrappers.ts b/src/legacy/core_plugins/interpreter/public/canvas/load_legacy_server_function_wrappers.ts deleted file mode 100644 index fed157846a1a1..0000000000000 --- a/src/legacy/core_plugins/interpreter/public/canvas/load_legacy_server_function_wrappers.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This file needs to be deleted by 8.0 release. It is here to load available - * server side functions and create a wrappers around them on client side, to - * execute them from client side. This functionality is used only by Canvas - * and all server side functions are in Canvas plugin. - * - * In 8.0 there will be no server-side functions, plugins will register only - * client side functions and if they need those to execute something on the - * server side, it should be respective function's internal implementation detail. - */ - -import { npSetup } from 'ui/new_platform'; - -export const { loadLegacyServerFunctionWrappers } = npSetup.plugins.expressions.__LEGACY; diff --git a/src/legacy/core_plugins/interpreter/public/interpreter.ts b/src/legacy/core_plugins/interpreter/public/interpreter.ts deleted file mode 100644 index 319a2779010c3..0000000000000 --- a/src/legacy/core_plugins/interpreter/public/interpreter.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import 'uiExports/interpreter'; -// @ts-ignore -import { register, registryFactory } from '@kbn/interpreter/common'; -import { npSetup } from 'ui/new_platform'; -import { registries } from './registries'; -import { Executor, ExpressionExecutor } from '../../../../plugins/expressions/public'; - -// Expose kbnInterpreter.register(specs) and kbnInterpreter.registries() globally so that plugins -// can register without a transpile step. -// TODO: This will be left behind in then legacy platform? -(global as any).kbnInterpreter = Object.assign( - (global as any).kbnInterpreter || {}, - registryFactory(registries) -); - -// TODO: This function will be left behind in the legacy platform. -let executorPromise: Promise | undefined; -export const getInterpreter = async () => { - if (!executorPromise) { - const executor = npSetup.plugins.expressions.__LEGACY.getExecutor(); - executorPromise = Promise.resolve(executor); - } - return await executorPromise; -}; - -// TODO: This function will be left behind in the legacy platform. -export const interpretAst: Executor['run'] = async (ast, context, handlers) => { - const { interpreter } = await getInterpreter(); - return await interpreter.interpretAst(ast, context, handlers); -}; diff --git a/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts b/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts deleted file mode 100644 index 0f37f33cc1b13..0000000000000 --- a/src/legacy/core_plugins/interpreter/public/registries.karma_mock.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import sinon from 'sinon'; - -export const functionsRegistry = {}; -export const renderersRegistry = {}; -export const typesRegistry = {}; -export const registries = { - browserFunctions: functionsRegistry, - renderers: renderersRegistry, - types: typesRegistry, - loadLegacyServerFunctionWrappers: () => Promise.resolve(), -}; - -const resetRegistry = (registry: any) => { - registry.wrapper = sinon.stub(); - registry.register = sinon.stub(); - registry.toJS = sinon.stub(); - registry.toArray = sinon.stub(); - registry.get = sinon.stub(); - registry.getProp = sinon.stub(); - registry.reset = sinon.stub(); -}; -const resetAll = () => Object.values(registries).forEach(resetRegistry); - -resetAll(); -afterEach(resetAll); diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js index 48d86e3628e49..51577456135d1 100644 --- a/src/legacy/core_plugins/kibana/index.js +++ b/src/legacy/core_plugins/kibana/index.js @@ -53,7 +53,7 @@ export default function(kibana) { }, uiExports: { - hacks: ['plugins/kibana/discover/legacy', 'plugins/kibana/dev_tools'], + hacks: ['plugins/kibana/dev_tools'], app: { id: 'kibana', title: 'Kibana', diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js b/src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js similarity index 96% rename from src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js rename to src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js index 9e74df08233da..edf65fdb56220 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/doc_table.js +++ b/src/legacy/core_plugins/kibana/public/__tests__/discover/doc_table.js @@ -16,18 +16,15 @@ * specific language governing permissions and limitations * under the License. */ - import angular from 'angular'; import expect from '@kbn/expect'; import _ from 'lodash'; import ngMock from 'ng_mock'; import 'ui/private'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; +import { pluginInstance } from './legacy'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; import hits from 'fixtures/real_hits'; -// Load the kibana app dependencies. - let $parentScope; let $scope; @@ -60,6 +57,7 @@ const destroy = function() { describe('docTable', function() { let $elem; + beforeEach(() => pluginInstance.initializeInnerAngular()); beforeEach(() => pluginInstance.initializeServices()); beforeEach(ngMock.module('app/discover')); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/fixed_scroll.js b/src/legacy/core_plugins/kibana/public/__tests__/discover/fixed_scroll.js similarity index 89% rename from src/legacy/core_plugins/kibana/public/discover/__tests__/directives/fixed_scroll.js rename to src/legacy/core_plugins/kibana/public/__tests__/discover/fixed_scroll.js index 49a0df54079ea..4a8736cc0d6a4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/fixed_scroll.js +++ b/src/legacy/core_plugins/kibana/public/__tests__/discover/fixed_scroll.js @@ -17,21 +17,33 @@ * under the License. */ +/* eslint-disable @kbn/eslint/no-restricted-paths */ + +import angular from 'angular'; import expect from '@kbn/expect'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; import ngMock from 'ng_mock'; import $ from 'jquery'; import sinon from 'sinon'; +import { PrivateProvider } from '../../../../../../plugins/kibana_legacy/public'; +import { FixedScrollProvider } from '../../../../../../plugins/discover/public/application/angular/directives/fixed_scroll'; +import { DebounceProviderTimeout } from '../../../../../../plugins/discover/public/application/angular/directives/debounce/debounce'; + +const testModuleName = 'fixedScroll'; + +angular + .module(testModuleName, []) + .provider('Private', PrivateProvider) + .service('debounce', ['$timeout', DebounceProviderTimeout]) + .directive('fixedScroll', FixedScrollProvider); + describe('FixedScroll directive', function() { const sandbox = sinon.createSandbox(); let compile; let flushPendingTasks; const trash = []; - beforeEach(() => pluginInstance.initializeServices()); - beforeEach(() => pluginInstance.initializeInnerAngular()); - beforeEach(ngMock.module('app/discover')); + beforeEach(ngMock.module(testModuleName)); beforeEach( ngMock.inject(function($compile, $rootScope, $timeout) { flushPendingTasks = function flushPendingTasks() { diff --git a/src/legacy/core_plugins/kibana/public/discover/legacy.ts b/src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts similarity index 80% rename from src/legacy/core_plugins/kibana/public/discover/legacy.ts rename to src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts index f08fd22c71850..ecda2a8c15395 100644 --- a/src/legacy/core_plugins/kibana/public/discover/legacy.ts +++ b/src/legacy/core_plugins/kibana/public/__tests__/discover/legacy.ts @@ -17,11 +17,11 @@ * under the License. */ -import { PluginInitializerContext } from 'kibana/public'; import { npSetup, npStart } from 'ui/new_platform'; -import { plugin } from './index'; +import { plugin } from '../../../../../../plugins/discover/public'; +import { coreMock } from '../../../../../../core/public/mocks'; +const context = coreMock.createPluginInitializerContext(); -// Legacy compatibility part - to be removed at cutover, replaced by a kibana.json file -export const pluginInstance = plugin({} as PluginInitializerContext); +export const pluginInstance = plugin(context); export const setup = pluginInstance.setup(npSetup.core, npSetup.plugins); export const start = pluginInstance.start(npStart.core, npStart.plugins); diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/lib/rows_headers.js b/src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js similarity index 98% rename from src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/lib/rows_headers.js rename to src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js index 9b63b8cd18f3e..5450a4127b63c 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/doc_table/lib/rows_headers.js +++ b/src/legacy/core_plugins/kibana/public/__tests__/discover/row_headers.js @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import angular from 'angular'; import _ from 'lodash'; import sinon from 'sinon'; @@ -24,7 +23,7 @@ import expect from '@kbn/expect'; import ngMock from 'ng_mock'; import { getFakeRow, getFakeRowVals } from 'fixtures/fake_row'; import $ from 'jquery'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; +import { pluginInstance } from './legacy'; import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; describe('Doc Table', function() { @@ -218,7 +217,7 @@ describe('Doc Table', function() { }); /** this no longer works with the new plugin approach - it('should render even when the row source contains a field with the same name as a meta field', function () { + it('should render even when the row source contains a field with the same name as a meta field', function () { setTimeout(() => { //this should be overridden by later changes }, 100); diff --git a/src/legacy/core_plugins/kibana/public/discover/_index.scss b/src/legacy/core_plugins/kibana/public/discover/_index.scss deleted file mode 100644 index 386472a9f6e01..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/_index.scss +++ /dev/null @@ -1,2 +0,0 @@ -// Discover plugin styles -@import 'np_ready/index'; diff --git a/src/legacy/core_plugins/kibana/public/discover/plugin.ts b/src/legacy/core_plugins/kibana/public/discover/plugin.ts deleted file mode 100644 index 702331529b879..0000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/plugin.ts +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { BehaviorSubject } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; -import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'kibana/public'; -import angular, { auto } from 'angular'; -import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public'; -import { - DataPublicPluginStart, - DataPublicPluginSetup, - esFilters, -} from '../../../../../plugins/data/public'; -import { registerFeature } from './np_ready/register_feature'; -import './kibana_services'; -import { EmbeddableStart, EmbeddableSetup } from '../../../../../plugins/embeddable/public'; -import { getInnerAngularModule, getInnerAngularModuleEmbeddable } from './get_inner_angular'; -import { getHistory, setAngularModule, setServices, setUrlTracker } from './kibana_services'; -import { NavigationPublicPluginStart as NavigationStart } from '../../../../../plugins/navigation/public'; -import { ChartsPluginStart } from '../../../../../plugins/charts/public'; -import { buildServices } from './build_services'; -import { SharePluginStart } from '../../../../../plugins/share/public'; -import { - KibanaLegacySetup, - AngularRenderedAppUpdater, -} from '../../../../../plugins/kibana_legacy/public'; -import { DiscoverSetup, DiscoverStart } from '../../../../../plugins/discover/public'; -import { HomePublicPluginSetup } from '../../../../../plugins/home/public'; -import { - VisualizationsStart, - VisualizationsSetup, -} from '../../../../../plugins/visualizations/public'; -import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public'; - -export interface DiscoverSetupPlugins { - uiActions: UiActionsSetup; - embeddable: EmbeddableSetup; - kibanaLegacy: KibanaLegacySetup; - home: HomePublicPluginSetup; - visualizations: VisualizationsSetup; - data: DataPublicPluginSetup; - discover: DiscoverSetup; -} -export interface DiscoverStartPlugins { - uiActions: UiActionsStart; - embeddable: EmbeddableStart; - navigation: NavigationStart; - charts: ChartsPluginStart; - data: DataPublicPluginStart; - share: SharePluginStart; - inspector: any; - visualizations: VisualizationsStart; - discover: DiscoverStart; -} -const innerAngularName = 'app/discover'; -const embeddableAngularName = 'app/discoverEmbeddable'; - -/** - * Contains Discover, one of the oldest parts of Kibana - * There are 2 kinds of Angular bootstrapped for rendering, additionally to the main Angular - * Discover provides embeddables, those contain a slimmer Angular - */ -export class DiscoverPlugin implements Plugin { - private servicesInitialized: boolean = false; - private innerAngularInitialized: boolean = false; - private embeddableInjector: auto.IInjectorService | null = null; - private getEmbeddableInjector: (() => Promise) | null = null; - private appStateUpdater = new BehaviorSubject(() => ({})); - private stopUrlTracking: (() => void) | undefined = undefined; - - /** - * why are those functions public? they are needed for some mocha tests - * can be removed once all is Jest - */ - public initializeInnerAngular?: () => void; - public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>; - - setup(core: CoreSetup, plugins: DiscoverSetupPlugins) { - const { - appMounted, - appUnMounted, - stop: stopUrlTracker, - setActiveUrl: setTrackedUrl, - } = createKbnUrlTracker({ - // we pass getter here instead of plain `history`, - // so history is lazily created (when app is mounted) - // this prevents redundant `#` when not in discover app - getHistory, - baseUrl: core.http.basePath.prepend('/app/kibana'), - defaultSubUrl: '#/discover', - storageKey: `lastUrl:${core.http.basePath.get()}:discover`, - navLinkUpdater$: this.appStateUpdater, - toastNotifications: core.notifications.toasts, - stateParams: [ - { - kbnUrlKey: '_g', - stateUpdate$: plugins.data.query.state$.pipe( - filter( - ({ changes }) => !!(changes.globalFilters || changes.time || changes.refreshInterval) - ), - map(({ state }) => ({ - ...state, - filters: state.filters?.filter(esFilters.isFilterPinned), - })) - ), - }, - ], - }); - setUrlTracker({ setTrackedUrl }); - this.stopUrlTracking = () => { - stopUrlTracker(); - }; - - this.getEmbeddableInjector = this.getInjector.bind(this); - plugins.discover.docViews.setAngularInjectorGetter(this.getEmbeddableInjector); - plugins.kibanaLegacy.registerLegacyApp({ - id: 'discover', - title: 'Discover', - updater$: this.appStateUpdater.asObservable(), - navLinkId: 'kibana:discover', - order: -1004, - euiIconType: 'discoverApp', - mount: async (params: AppMountParameters) => { - if (!this.initializeServices) { - throw Error('Discover plugin method initializeServices is undefined'); - } - if (!this.initializeInnerAngular) { - throw Error('Discover plugin method initializeInnerAngular is undefined'); - } - appMounted(); - await this.initializeServices(); - await this.initializeInnerAngular(); - - // make sure the index pattern list is up to date - const [, { data: dataStart }] = await core.getStartServices(); - await dataStart.indexPatterns.clearCache(); - const { renderApp } = await import('./np_ready/application'); - const unmount = await renderApp(innerAngularName, params.element); - return () => { - unmount(); - appUnMounted(); - }; - }, - }); - registerFeature(plugins.home); - this.registerEmbeddable(core, plugins); - } - - start(core: CoreStart, plugins: DiscoverStartPlugins) { - // we need to register the application service at setup, but to render it - // there are some start dependencies necessary, for this reason - // initializeInnerAngular + initializeServices are assigned at start and used - // when the application/embeddable is mounted - this.initializeInnerAngular = async () => { - if (this.innerAngularInitialized) { - return; - } - // this is used by application mount and tests - const module = getInnerAngularModule(innerAngularName, core, plugins); - setAngularModule(module); - this.innerAngularInitialized = true; - }; - - this.initializeServices = async () => { - if (this.servicesInitialized) { - return { core, plugins }; - } - const services = await buildServices(core, plugins, getHistory); - setServices(services); - this.servicesInitialized = true; - - return { core, plugins }; - }; - } - - stop() { - if (this.stopUrlTracking) { - this.stopUrlTracking(); - } - } - - /** - * register embeddable with a slimmer embeddable version of inner angular - */ - private async registerEmbeddable( - core: CoreSetup, - plugins: DiscoverSetupPlugins - ) { - const { SearchEmbeddableFactory } = await import('./np_ready/embeddable'); - - if (!this.getEmbeddableInjector) { - throw Error('Discover plugin method getEmbeddableInjector is undefined'); - } - - const getStartServices = async () => { - const [coreStart, deps] = await core.getStartServices(); - return { - executeTriggerActions: deps.uiActions.executeTriggerActions, - isEditable: () => coreStart.application.capabilities.discover.save as boolean, - }; - }; - - const factory = new SearchEmbeddableFactory(getStartServices, this.getEmbeddableInjector); - plugins.embeddable.registerEmbeddableFactory(factory.type, factory); - } - - private async getInjector() { - if (!this.embeddableInjector) { - if (!this.initializeServices) { - throw Error('Discover plugin getEmbeddableInjector: initializeServices is undefined'); - } - const { core, plugins } = await this.initializeServices(); - getInnerAngularModuleEmbeddable(embeddableAngularName, core, plugins); - const mountpoint = document.createElement('div'); - this.embeddableInjector = angular.bootstrap(mountpoint, [embeddableAngularName]); - } - - return this.embeddableInjector; - } -} diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png deleted file mode 100644 index 22136049b494a..0000000000000 Binary files a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/azure_metrics/screenshot.png and /dev/null differ diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg deleted file mode 100644 index a93c83b4b4ae0..0000000000000 --- a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/azure.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/oracle.svg b/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/oracle.svg deleted file mode 100644 index 78db57f914818..0000000000000 --- a/src/legacy/core_plugins/kibana/public/home/tutorial_resources/logos/oracle.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/legacy/core_plugins/kibana/public/index.scss b/src/legacy/core_plugins/kibana/public/index.scss index 26805554370b9..6a2e65e3a9ff5 100644 --- a/src/legacy/core_plugins/kibana/public/index.scss +++ b/src/legacy/core_plugins/kibana/public/index.scss @@ -7,9 +7,6 @@ // Public UI styles @import 'src/legacy/ui/public/index'; -// Discover styles -@import 'discover/index'; - // Has to come after visualize because of some // bad cascading in the Editor layout @import '../../../../plugins/maps_legacy/public/index'; diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js index ea0d5ad3790b1..ad67a74121cc9 100644 --- a/src/legacy/core_plugins/kibana/public/kibana.js +++ b/src/legacy/core_plugins/kibana/public/kibana.js @@ -42,7 +42,6 @@ import 'uiExports/shareContextMenuExtensions'; import 'uiExports/interpreter'; import 'ui/autoload/all'; -import './discover/legacy'; import './management'; import './dev_tools'; import { showAppRedirectNotification } from '../../../../plugins/kibana_legacy/public'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap index ed65db10e0acb..1545ab8cb9b1c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/__snapshots__/create_index_pattern_wizard.test.tsx.snap @@ -149,6 +149,8 @@ exports[`CreateIndexPatternWizard renders time field step when step is set to 2 indexPatternsService={ Object { "clearCache": [MockFunction], + "createField": [MockFunction], + "createFieldList": [MockFunction], "ensureDefaultIndexPattern": [MockFunction], "get": [MockFunction], "make": [Function], diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx index 564f115cf2c48..3b865f7d5e1ea 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/create_edit_field/create_edit_field.tsx @@ -24,8 +24,8 @@ import { FieldEditor } from 'ui/field_editor'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { HttpStart, DocLinksStart } from 'src/core/public'; +import { IndexPattern, DataPublicPluginStart } from 'src/plugins/data/public'; import { IndexHeader } from '../index_header'; -import { IndexPattern, IndexPatternField } from '../../../../../../../../../plugins/data/public'; import { ChromeDocTitle, NotificationsStart } from '../../../../../../../../../core/public'; import { TAB_SCRIPTED_FIELDS, TAB_INDEXED_FIELDS } from '../constants'; @@ -36,6 +36,7 @@ interface CreateEditFieldProps extends RouteComponentProps { fieldFormatEditors: any; getConfig: (name: string) => any; services: { + dataStart: DataPublicPluginStart; notifications: NotificationsStart; docTitle: ChromeDocTitle; getHttpStart: () => HttpStart; @@ -63,10 +64,14 @@ export const CreateEditField = withRouter( const field = mode === 'edit' && fieldName ? indexPattern.fields.getByName(fieldName) - : new IndexPatternField(indexPattern, { - scripted: true, - type: 'number', - }); + : services.dataStart.indexPatterns.createField( + indexPattern, + { + scripted: true, + type: 'number', + }, + false + ); const url = `/management/kibana/index_patterns/${indexPattern.id}`; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js index e2f387c0291a7..ab1fa546e5ea8 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/edit_index_pattern/index.js @@ -112,6 +112,7 @@ const renderCreateEditField = ($scope, $route, getConfig, fieldFormatEditors) => fieldFormatEditors={fieldFormatEditors} getConfig={getConfig} services={{ + dataStart: npStart.plugins.data, getHttpStart: () => npStart.core.http, notifications: npStart.core.notifications, docTitle: npStart.core.chrome.docTitle, diff --git a/src/legacy/ui/public/field_editor/field_editor.test.tsx b/src/legacy/ui/public/field_editor/field_editor.test.tsx index 5716305b51483..92264fbfbc94d 100644 --- a/src/legacy/ui/public/field_editor/field_editor.test.tsx +++ b/src/legacy/ui/public/field_editor/field_editor.test.tsx @@ -24,7 +24,7 @@ import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers'; import { Field, IndexPattern, - IndexPatternFieldList, + IIndexPatternFieldList, FieldFormatInstanceType, } from 'src/plugins/data/public'; import { HttpStart } from '../../../../core/public'; @@ -114,7 +114,7 @@ describe('FieldEditor', () => { beforeEach(() => { indexPattern = ({ - fields: fields as IndexPatternFieldList, + fields: fields as IIndexPatternFieldList, } as unknown) as IndexPattern; npStart.plugins.data.fieldFormats.getDefaultType = jest.fn( diff --git a/src/legacy/ui/public/styles/_legacy/components/_table.scss b/src/legacy/ui/public/styles/_legacy/components/_table.scss index c9472cbd2faa7..d0ac9d6f79862 100644 --- a/src/legacy/ui/public/styles/_legacy/components/_table.scss +++ b/src/legacy/ui/public/styles/_legacy/components/_table.scss @@ -1,4 +1,4 @@ -@import '../../../../../core_plugins/kibana/public/discover/np_ready/mixins'; +@import '../../../../../../plugins/discover/public/application/mixins'; .table { // Nesting diff --git a/src/optimize/bundles_route/dynamic_asset_response.ts b/src/optimize/bundles_route/dynamic_asset_response.ts index a020c6935eeec..2f5395341abb1 100644 --- a/src/optimize/bundles_route/dynamic_asset_response.ts +++ b/src/optimize/bundles_route/dynamic_asset_response.ts @@ -21,6 +21,7 @@ import Fs from 'fs'; import { resolve } from 'path'; import { promisify } from 'util'; +import Accept from 'accept'; import Boom from 'boom'; import Hapi from 'hapi'; @@ -37,6 +38,41 @@ const asyncOpen = promisify(Fs.open); const asyncClose = promisify(Fs.close); const asyncFstat = promisify(Fs.fstat); +async function tryToOpenFile(filePath: string) { + try { + return await asyncOpen(filePath, 'r'); + } catch (e) { + if (e.code === 'ENOENT') { + return undefined; + } else { + throw e; + } + } +} + +async function selectCompressedFile(acceptEncodingHeader: string | undefined, path: string) { + let fd: number | undefined; + let fileEncoding: 'gzip' | 'br' | undefined; + + const supportedEncodings = Accept.encodings(acceptEncodingHeader, ['br', 'gzip']); + + if (supportedEncodings[0] === 'br') { + fileEncoding = 'br'; + fd = await tryToOpenFile(`${path}.br`); + } + if (!fd && supportedEncodings.includes('gzip')) { + fileEncoding = 'gzip'; + fd = await tryToOpenFile(`${path}.gz`); + } + if (!fd) { + fileEncoding = undefined; + // Use raw open to trigger exception if it does not exist + fd = await asyncOpen(path, 'r'); + } + + return { fd, fileEncoding }; +} + /** * Create a Hapi response for the requested path. This is designed * to replicate a subset of the features provided by Hapi's Inert @@ -74,6 +110,7 @@ export async function createDynamicAssetResponse({ isDist: boolean; }) { let fd: number | undefined; + let fileEncoding: 'gzip' | 'br' | undefined; try { const path = resolve(bundlesPath, request.params.path); @@ -86,7 +123,7 @@ export async function createDynamicAssetResponse({ // we use and manage a file descriptor mostly because // that's what Inert does, and since we are accessing // the file 2 or 3 times per request it seems logical - fd = await asyncOpen(path, 'r'); + ({ fd, fileEncoding } = await selectCompressedFile(request.headers['accept-encoding'], path)); const stat = await asyncFstat(fd); const hash = isDist ? undefined : await getFileHash(fileHashCache, path, stat, fd); @@ -113,6 +150,12 @@ export async function createDynamicAssetResponse({ response.header('cache-control', 'must-revalidate'); } + // If we manually selected a compressed file, specify the encoding header. + // Otherwise, let Hapi automatically gzip the response. + if (fileEncoding) { + response.header('content-encoding', fileEncoding); + } + return response; } catch (error) { if (fd) { diff --git a/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts b/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts index 1170c9edd2366..ce3155919bd1d 100644 --- a/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts +++ b/src/plugins/console/server/lib/spec_definitions/js/aggregations.ts @@ -148,7 +148,7 @@ const rules = { shard_size: 10, order: { __template: { - _term: 'asc', + _key: 'asc', }, _term: { __one_of: ['asc', 'desc'] }, _count: { __one_of: ['asc', 'desc'] }, diff --git a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx index 4d15e7e899fa8..ff4e50ba8c327 100644 --- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx @@ -39,7 +39,7 @@ export interface ClonePanelActionContext { export class ClonePanelAction implements ActionByType { public readonly type = ACTION_CLONE_PANEL; public readonly id = ACTION_CLONE_PANEL; - public order = 11; + public order = 45; constructor(private core: CoreStart) {} diff --git a/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx b/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx index ddc255295e89b..5526af2f83850 100644 --- a/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx +++ b/src/plugins/dashboard/public/application/actions/replace_panel_action.tsx @@ -37,7 +37,7 @@ export interface ReplacePanelActionContext { export class ReplacePanelAction implements ActionByType { public readonly type = ACTION_REPLACE_PANEL; public readonly id = ACTION_REPLACE_PANEL; - public order = 11; + public order = 3; constructor( private core: CoreStart, diff --git a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx index 5dab21ff671b4..40231de7597f1 100644 --- a/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx +++ b/src/plugins/dashboard/public/application/tests/dashboard_container.test.tsx @@ -46,7 +46,7 @@ test('DashboardContainer in edit mode shows edit mode actions', async () => { const editModeAction = createEditModeAction(); uiActionsSetup.registerAction(editModeAction); - uiActionsSetup.attachAction(CONTEXT_MENU_TRIGGER, editModeAction); + uiActionsSetup.addTriggerAction(CONTEXT_MENU_TRIGGER, editModeAction); setup.registerEmbeddableFactory( CONTACT_CARD_EMBEDDABLE, new ContactCardEmbeddableFactory((() => null) as any, {} as any) diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx index 7de054f2eaa9c..b28822120b31e 100644 --- a/src/plugins/dashboard/public/plugin.tsx +++ b/src/plugins/dashboard/public/plugin.tsx @@ -136,7 +136,7 @@ export class DashboardPlugin ): Setup { const expandPanelAction = new ExpandPanelAction(); uiActions.registerAction(expandPanelAction); - uiActions.attachAction(CONTEXT_MENU_TRIGGER, expandPanelAction); + uiActions.attachAction(CONTEXT_MENU_TRIGGER, expandPanelAction.id); const startServices = core.getStartServices(); if (share) { @@ -310,11 +310,11 @@ export class DashboardPlugin plugins.embeddable.getEmbeddableFactories ); uiActions.registerAction(changeViewAction); - uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction); + uiActions.attachAction(CONTEXT_MENU_TRIGGER, changeViewAction.id); const clonePanelAction = new ClonePanelAction(core); uiActions.registerAction(clonePanelAction); - uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction); + uiActions.attachAction(CONTEXT_MENU_TRIGGER, clonePanelAction.id); const savedDashboardLoader = createSavedDashboardLoader({ savedObjectsClient: core.savedObjects.client, diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index bd20c6f632a3a..ebaac6b745bec 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -42,6 +42,7 @@ export function createFilterAction( return createAction({ type: ACTION_GLOBAL_APPLY_FILTER, id: ACTION_GLOBAL_APPLY_FILTER, + getIconType: () => 'filter', getDisplayName: () => { return i18n.translate('data.filter.applyFilterActionTitle', { defaultMessage: 'Apply filter to current view', diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 75deff23ce20d..8e48214ab0f91 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -59,6 +59,7 @@ import { changeTimeFilter, mapAndFlattenFilters, extractTimeFilter, + convertRangeFilterToTimeRangeString, } from './query'; // Filter helpers namespace: @@ -96,6 +97,7 @@ export const esFilters = { onlyDisabledFiltersChanged, changeTimeFilter, + convertRangeFilterToTimeRangeString, mapAndFlattenFilters, extractTimeFilter, }; @@ -252,11 +254,12 @@ export const indexPatterns = { export { IndexPatternsContract, IndexPattern, + IIndexPatternFieldList, Field as IndexPatternField, TypeMeta as IndexPatternTypeMeta, AggregationRestrictions as IndexPatternAggRestrictions, // TODO: exported only in stub_index_pattern test. Move into data plugin and remove export. - FieldList as IndexPatternFieldList, + getIndexPatternFieldListCreator, Field, } from './index_patterns'; diff --git a/src/plugins/data/public/index_patterns/fields/field.ts b/src/plugins/data/public/index_patterns/fields/field.ts index d83c0a7d3445e..12db09bbb846f 100644 --- a/src/plugins/data/public/index_patterns/fields/field.ts +++ b/src/plugins/data/public/index_patterns/fields/field.ts @@ -18,15 +18,26 @@ */ import { i18n } from '@kbn/i18n'; +import { ToastsStart } from 'kibana/public'; // @ts-ignore import { ObjDefine } from './obj_define'; import { IndexPattern } from '../index_patterns'; -import { getNotifications, getFieldFormats } from '../../services'; -import { IFieldType, getKbnFieldType, IFieldSubType, FieldFormat } from '../../../common'; -import { shortenDottedString } from '../../../common/utils'; +import { + IFieldType, + getKbnFieldType, + IFieldSubType, + FieldFormat, + shortenDottedString, +} from '../../../common'; +import { FieldFormatsStart } from '../../field_formats'; export type FieldSpec = Record; +interface FieldDependencies { + fieldFormats: FieldFormatsStart; + toastNotifications: ToastsStart; +} + export class Field implements IFieldType { name: string; type: string; @@ -52,7 +63,8 @@ export class Field implements IFieldType { constructor( indexPattern: IndexPattern, spec: FieldSpec | Field, - shortDotsEnable: boolean = false + shortDotsEnable: boolean, + { fieldFormats, toastNotifications }: FieldDependencies ) { // unwrap old instances of Field if (spec instanceof Field) spec = spec.$$spec; @@ -77,9 +89,8 @@ export class Field implements IFieldType { values: { name: spec.name, title: indexPattern.title }, defaultMessage: 'Field {name} in indexPattern {title} is using an unknown field type.', }); - const { toasts } = getNotifications(); - toasts.addDanger({ + toastNotifications.addDanger({ title, text, }); @@ -90,11 +101,9 @@ export class Field implements IFieldType { let format = spec.format; if (!FieldFormat.isInstanceOfFieldFormat(format)) { - const fieldFormatsService = getFieldFormats(); - format = indexPattern.fieldFormatMap[spec.name] || - fieldFormatsService.getDefaultInstance(spec.type, spec.esTypes); + fieldFormats.getDefaultInstance(spec.type, spec.esTypes); } const indexed = !!spec.indexed; diff --git a/src/plugins/data/public/index_patterns/fields/field_list.ts b/src/plugins/data/public/index_patterns/fields/field_list.ts index 9772370199b24..0631e00a1fb62 100644 --- a/src/plugins/data/public/index_patterns/fields/field_list.ts +++ b/src/plugins/data/public/index_patterns/fields/field_list.ts @@ -18,13 +18,20 @@ */ import { findIndex } from 'lodash'; +import { ToastsStart } from 'kibana/public'; import { IndexPattern } from '../index_patterns'; import { IFieldType } from '../../../common'; import { Field, FieldSpec } from './field'; +import { FieldFormatsStart } from '../../field_formats'; type FieldMap = Map; -export interface IFieldList extends Array { +interface FieldListDependencies { + fieldFormats: FieldFormatsStart; + toastNotifications: ToastsStart; +} + +export interface IIndexPatternFieldList extends Array { getByName(name: Field['name']): Field | undefined; getByType(type: Field['type']): Field[]; add(field: FieldSpec): void; @@ -32,51 +39,70 @@ export interface IFieldList extends Array { update(field: FieldSpec): void; } -export class FieldList extends Array implements IFieldList { - private byName: FieldMap = new Map(); - private groups: Map = new Map(); - private indexPattern: IndexPattern; - private shortDotsEnable: boolean; - private setByName = (field: Field) => this.byName.set(field.name, field); - private setByGroup = (field: Field) => { - if (typeof this.groups.get(field.type) === 'undefined') { - this.groups.set(field.type, new Map()); - } - this.groups.get(field.type)!.set(field.name, field); - }; - private removeByGroup = (field: IFieldType) => this.groups.get(field.type)!.delete(field.name); +export type CreateIndexPatternFieldList = ( + indexPattern: IndexPattern, + specs?: FieldSpec[], + shortDotsEnable?: boolean +) => IIndexPatternFieldList; - constructor(indexPattern: IndexPattern, specs: FieldSpec[] = [], shortDotsEnable = false) { - super(); - this.indexPattern = indexPattern; - this.shortDotsEnable = shortDotsEnable; +export const getIndexPatternFieldListCreator = ({ + fieldFormats, + toastNotifications, +}: FieldListDependencies): CreateIndexPatternFieldList => (...fieldListParams) => { + class FieldList extends Array implements IIndexPatternFieldList { + private byName: FieldMap = new Map(); + private groups: Map = new Map(); + private indexPattern: IndexPattern; + private shortDotsEnable: boolean; + private setByName = (field: Field) => this.byName.set(field.name, field); + private setByGroup = (field: Field) => { + if (typeof this.groups.get(field.type) === 'undefined') { + this.groups.set(field.type, new Map()); + } + this.groups.get(field.type)!.set(field.name, field); + }; + private removeByGroup = (field: IFieldType) => this.groups.get(field.type)!.delete(field.name); - specs.map(field => this.add(field)); - } + constructor(indexPattern: IndexPattern, specs: FieldSpec[] = [], shortDotsEnable = false) { + super(); + this.indexPattern = indexPattern; + this.shortDotsEnable = shortDotsEnable; - getByName = (name: Field['name']) => this.byName.get(name); - getByType = (type: Field['type']) => [...(this.groups.get(type) || new Map()).values()]; - add = (field: FieldSpec) => { - const newField = new Field(this.indexPattern, field, this.shortDotsEnable); - this.push(newField); - this.setByName(newField); - this.setByGroup(newField); - }; + specs.map(field => this.add(field)); + } - remove = (field: IFieldType) => { - this.removeByGroup(field); - this.byName.delete(field.name); + getByName = (name: Field['name']) => this.byName.get(name); + getByType = (type: Field['type']) => [...(this.groups.get(type) || new Map()).values()]; + add = (field: FieldSpec) => { + const newField = new Field(this.indexPattern, field, this.shortDotsEnable, { + fieldFormats, + toastNotifications, + }); + this.push(newField); + this.setByName(newField); + this.setByGroup(newField); + }; - const fieldIndex = findIndex(this, { name: field.name }); - this.splice(fieldIndex, 1); - }; + remove = (field: IFieldType) => { + this.removeByGroup(field); + this.byName.delete(field.name); - update = (field: FieldSpec) => { - const newField = new Field(this.indexPattern, field, this.shortDotsEnable); - const index = this.findIndex(f => f.name === newField.name); - this.splice(index, 1, newField); - this.setByName(newField); - this.removeByGroup(newField); - this.setByGroup(newField); - }; -} + const fieldIndex = findIndex(this, { name: field.name }); + this.splice(fieldIndex, 1); + }; + + update = (field: FieldSpec) => { + const newField = new Field(this.indexPattern, field, this.shortDotsEnable, { + fieldFormats, + toastNotifications, + }); + const index = this.findIndex(f => f.name === newField.name); + this.splice(index, 1, newField); + this.setByName(newField); + this.removeByGroup(newField); + this.setByGroup(newField); + }; + } + + return new FieldList(...fieldListParams); +}; diff --git a/src/plugins/data/public/index_patterns/index.ts b/src/plugins/data/public/index_patterns/index.ts index dcf799184b01c..e05db0e4d4cec 100644 --- a/src/plugins/data/public/index_patterns/index.ts +++ b/src/plugins/data/public/index_patterns/index.ts @@ -29,7 +29,7 @@ export { export { getRoutes } from './utils'; export { flattenHitWrapper, formatHitProvider } from './index_patterns'; -export { Field, FieldList } from './fields'; +export { getIndexPatternFieldListCreator, Field, IIndexPatternFieldList } from './fields'; // TODO: figure out how to replace IndexPatterns in get_inner_angular. export { diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts index 768029136879d..f39be78433710 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_pattern.ts @@ -32,7 +32,7 @@ import { ES_FIELD_TYPES, KBN_FIELD_TYPES, IIndexPattern, IFieldType } from '../. import { findByTitle, getRoutes } from '../utils'; import { IndexPatternMissingIndices } from '../lib'; -import { Field, FieldList, IFieldList } from '../fields'; +import { Field, IIndexPatternFieldList, getIndexPatternFieldListCreator } from '../fields'; import { createFieldsFetcher } from './_fields_fetcher'; import { formatHitProvider } from './format_hit'; import { flattenHitWrapper } from './flatten_hit'; @@ -51,7 +51,7 @@ export class IndexPattern implements IIndexPattern { public type?: string; public fieldFormatMap: any; public typeMeta?: TypeMeta; - public fields: IFieldList; + public fields: IIndexPatternFieldList; public timeFieldName: string | undefined; public formatHit: any; public formatField: any; @@ -106,7 +106,12 @@ export class IndexPattern implements IIndexPattern { this.shortDotsEnable = this.getConfig('shortDots:enable'); this.metaFields = this.getConfig('metaFields'); - this.fields = new FieldList(this, [], this.shortDotsEnable); + this.createFieldList = getIndexPatternFieldListCreator({ + fieldFormats: getFieldFormats(), + toastNotifications: getNotifications().toasts, + }); + + this.fields = this.createFieldList(this, [], this.shortDotsEnable); this.fieldsFetcher = createFieldsFetcher(this, apiClient, this.getConfig('metaFields')); this.flattenHit = flattenHitWrapper(this, this.getConfig('metaFields')); this.formatHit = formatHitProvider( @@ -131,7 +136,7 @@ export class IndexPattern implements IIndexPattern { private initFields(input?: any) { const newValue = input || this.fields; - this.fields = new FieldList(this, newValue, this.shortDotsEnable); + this.fields = this.createFieldList(this, newValue, this.shortDotsEnable); } private isFieldRefreshRequired(): boolean { @@ -281,7 +286,11 @@ export class IndexPattern implements IIndexPattern { filterable: true, searchable: true, }, - false + false, + { + fieldFormats: getFieldFormats(), + toastNotifications: getNotifications().toasts, + } ) ); diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts index cf1f83d0e28cb..fc0be270e9c50 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.test.ts @@ -19,12 +19,13 @@ // eslint-disable-next-line max-classes-per-file import { IndexPatternsService } from './index_patterns'; -import { - SavedObjectsClientContract, - HttpSetup, - SavedObjectsFindResponsePublic, - CoreStart, -} from 'kibana/public'; +import { SavedObjectsClientContract, SavedObjectsFindResponsePublic } from 'kibana/public'; +import { coreMock, httpServiceMock } from '../../../../../core/public/mocks'; +import { fieldFormatsServiceMock } from '../../field_formats/mocks'; + +const core = coreMock.createStart(); +const http = httpServiceMock.createStartContract(); +const fieldFormats = fieldFormatsServiceMock.createStartContract(); jest.mock('./index_pattern', () => { class IndexPattern { @@ -61,10 +62,7 @@ describe('IndexPatterns', () => { }) as Promise> ); - const core = {} as CoreStart; - const http = {} as HttpSetup; - - indexPatterns = new IndexPatternsService(core, savedObjectsClient, http); + indexPatterns = new IndexPatternsService(core, savedObjectsClient, http, fieldFormats); }); test('does cache gets for the same id', async () => { diff --git a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts index b5d66a6aab60a..515f2e7cf95ee 100644 --- a/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/public/index_patterns/index_patterns/index_patterns.ts @@ -32,28 +32,60 @@ import { createEnsureDefaultIndexPattern, EnsureDefaultIndexPattern, } from './ensure_default_index_pattern'; +import { + getIndexPatternFieldListCreator, + CreateIndexPatternFieldList, + Field, + FieldSpec, +} from '../fields'; +import { FieldFormatsStart } from '../../field_formats'; const indexPatternCache = createIndexPatternCache(); type IndexPatternCachedFieldType = 'id' | 'title'; +export interface IndexPatternSavedObjectAttrs { + title: string; +} + export class IndexPatternsService { private config: IUiSettingsClient; private savedObjectsClient: SavedObjectsClientContract; - private savedObjectsCache?: Array>> | null; + private savedObjectsCache?: Array> | null; private apiClient: IndexPatternsApiClient; ensureDefaultIndexPattern: EnsureDefaultIndexPattern; - - constructor(core: CoreStart, savedObjectsClient: SavedObjectsClientContract, http: HttpStart) { + createFieldList: CreateIndexPatternFieldList; + createField: ( + indexPattern: IndexPattern, + spec: FieldSpec | Field, + shortDotsEnable: boolean + ) => Field; + + constructor( + core: CoreStart, + savedObjectsClient: SavedObjectsClientContract, + http: HttpStart, + fieldFormats: FieldFormatsStart + ) { this.apiClient = new IndexPatternsApiClient(http); this.config = core.uiSettings; this.savedObjectsClient = savedObjectsClient; this.ensureDefaultIndexPattern = createEnsureDefaultIndexPattern(core); + this.createFieldList = getIndexPatternFieldListCreator({ + fieldFormats, + toastNotifications: core.notifications.toasts, + }); + this.createField = (indexPattern, spec, shortDotsEnable) => { + return new Field(indexPattern, spec, shortDotsEnable, { + fieldFormats, + toastNotifications: core.notifications.toasts, + }); + }; } private async refreshSavedObjectsCache() { this.savedObjectsCache = ( - await this.savedObjectsClient.find>({ + await this.savedObjectsClient.find({ type: 'index-pattern', fields: ['title'], perPage: 10000, diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index ba1df89c41358..7307c93139d59 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -57,6 +57,8 @@ const createStartContract = (): Start => { SearchBar: jest.fn(), }, indexPatterns: ({ + createField: jest.fn(() => {}), + createFieldList: jest.fn(() => []), ensureDefaultIndexPattern: jest.fn(), make: () => ({ fieldsFetcher: { diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index f3a88287313a0..08796216db1e0 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -126,12 +126,12 @@ export class DataPublicPlugin implements Plugin boolean; changeTimeFilter: typeof changeTimeFilter; + convertRangeFilterToTimeRangeString: typeof convertRangeFilterToTimeRangeString; mapAndFlattenFilters: (filters: import("../common").Filter[]) => import("../common").Filter[]; extractTimeFilter: typeof extractTimeFilter; }; @@ -436,7 +438,8 @@ class Field implements IFieldType { // // (undocumented) $$spec: FieldSpec; - constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable?: boolean); + // Warning: (ae-forgotten-export) The symbol "FieldDependencies" needs to be exported by the entry point index.d.ts + constructor(indexPattern: IndexPattern, spec: FieldSpec | Field, shortDotsEnable: boolean, { fieldFormats, toastNotifications }: FieldDependencies); // (undocumented) aggregatable?: boolean; // (undocumented) @@ -657,6 +660,13 @@ export function getDefaultQuery(language?: QueryLanguage): { // @public (undocumented) export function getEsPreference(uiSettings: IUiSettingsClient_2, sessionId?: string): any; +// Warning: (ae-forgotten-export) The symbol "FieldListDependencies" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "CreateIndexPatternFieldList" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "getIndexPatternFieldListCreator" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const getIndexPatternFieldListCreator: ({ fieldFormats, toastNotifications, }: FieldListDependencies) => CreateIndexPatternFieldList; + // Warning: (ae-missing-release-tag) "getKbnTypeNames" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public @@ -828,6 +838,22 @@ export interface IIndexPattern { type?: string; } +// Warning: (ae-missing-release-tag) "IIndexPatternFieldList" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface IIndexPatternFieldList extends Array { + // (undocumented) + add(field: FieldSpec): void; + // (undocumented) + getByName(name: Field['name']): Field | undefined; + // (undocumented) + getByType(type: Field['type']): Field[]; + // (undocumented) + remove(field: IFieldType): void; + // (undocumented) + update(field: FieldSpec): void; +} + // Warning: (ae-missing-release-tag) "IKibanaSearchRequest" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -869,10 +895,8 @@ export class IndexPattern implements IIndexPattern { _fetchFields(): Promise; // (undocumented) fieldFormatMap: any; - // Warning: (ae-forgotten-export) The symbol "IFieldList" needs to be exported by the entry point index.d.ts - // // (undocumented) - fields: IFieldList; + fields: IIndexPatternFieldList; // (undocumented) fieldsFetcher: any; // (undocumented) @@ -987,23 +1011,6 @@ export interface IndexPatternAttributes { typeMeta: string; } -// Warning: (ae-missing-release-tag) "FieldList" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) -export class IndexPatternFieldList extends Array implements IFieldList { - constructor(indexPattern: IndexPattern, specs?: FieldSpec[], shortDotsEnable?: boolean); - // (undocumented) - add: (field: Record) => void; - // (undocumented) - getByName: (name: string) => Field | undefined; - // (undocumented) - getByType: (type: string) => any[]; - // (undocumented) - remove: (field: IFieldType) => void; - // (undocumented) - update: (field: Record) => void; -} - // Warning: (ae-missing-release-tag) "indexPatterns" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1351,7 +1358,7 @@ export interface QueryState { // Warning: (ae-missing-release-tag) "QueryStringInput" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const QueryStringInput: React.FC>; +export const QueryStringInput: React.FC>; // @public (undocumented) export type QuerySuggestion = QuerySuggestionBasic | QuerySuggestionField; @@ -1563,8 +1570,8 @@ export const search: { // Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "screenTitle" | "dataTestSubj" | "customSubmitButton" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "indexPatterns" | "refreshInterval" | "customSubmitButton" | "screenTitle" | "dataTestSubj" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "onRefresh" | "timeHistory" | "onFiltersUpdated" | "onRefreshChange">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; }; // Warning: (ae-forgotten-export) The symbol "SearchBarOwnProps" needs to be exported by the entry point index.d.ts @@ -1783,52 +1790,53 @@ export type TSearchStrategyProvider = (context: ISearc // src/plugins/data/common/es_query/filters/match_all_filter.ts:28:3 - (ae-forgotten-export) The symbol "MatchAllFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrase_filter.ts:33:3 - (ae-forgotten-export) The symbol "PhraseFilterMeta" needs to be exported by the entry point index.d.ts // src/plugins/data/common/es_query/filters/phrases_filter.ts:31:3 - (ae-forgotten-export) The symbol "PhrasesFilterMeta" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:65:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:135:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:177:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:236:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:375:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:375:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:375:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:375:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:377:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:378:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:387:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:388:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:389:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:393:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:394:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:398:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FilterLabel" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "FILTERS" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "getDisplayValueFromFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "generateFilters" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "changeTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "convertRangeFilterToTimeRangeString" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:66:23 - (ae-forgotten-export) The symbol "extractTimeFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "buildEsQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "getEsQueryConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "luceneStringToDsl" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:137:21 - (ae-forgotten-export) The symbol "decorateQuery" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "FieldFormatsRegistry" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BoolFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "BytesFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "ColorFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "DurationFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "IpFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "NumberFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "PercentFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "RelativeDateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "SourceFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StaticLookupFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "UrlFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "StringFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:179:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "getFromSavedObject" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "getRoutes" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:378:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:378:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:378:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:378:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:380:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:381:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:390:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:391:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:392:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:396:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:397:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:400:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:401:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:404:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts // src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/query/timefilter/index.ts b/src/plugins/data/public/query/timefilter/index.ts index 034af03842ab8..a5885a59f60ed 100644 --- a/src/plugins/data/public/query/timefilter/index.ts +++ b/src/plugins/data/public/query/timefilter/index.ts @@ -23,5 +23,5 @@ export * from './types'; export { Timefilter, TimefilterContract } from './timefilter'; export { TimeHistory, TimeHistoryContract } from './time_history'; export { getTime, calculateBounds } from './get_time'; -export { changeTimeFilter } from './lib/change_time_filter'; +export { changeTimeFilter, convertRangeFilterToTimeRangeString } from './lib/change_time_filter'; export { extractTimeFilter } from './lib/extract_time_filter'; diff --git a/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts b/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts index 8da83580ef5d6..cbbf2f2754312 100644 --- a/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts +++ b/src/plugins/data/public/query/timefilter/lib/change_time_filter.ts @@ -20,7 +20,7 @@ import moment from 'moment'; import { keys } from 'lodash'; import { TimefilterContract } from '../../timefilter'; -import { RangeFilter } from '../../../../common'; +import { RangeFilter, TimeRange } from '../../../../common'; export function convertRangeFilterToTimeRange(filter: RangeFilter) { const key = keys(filter.range)[0]; @@ -32,6 +32,14 @@ export function convertRangeFilterToTimeRange(filter: RangeFilter) { }; } +export function convertRangeFilterToTimeRangeString(filter: RangeFilter): TimeRange { + const { from, to } = convertRangeFilterToTimeRange(filter); + return { + from: from?.toISOString(), + to: to?.toISOString(), + }; +} + export function changeTimeFilter(timeFilter: TimefilterContract, filter: RangeFilter) { timeFilter.setTime(convertRangeFilterToTimeRange(filter)); } diff --git a/src/plugins/data/public/search/aggs/agg_config.ts b/src/plugins/data/public/search/aggs/agg_config.ts index 973c69e3d4f5f..86a2c3e0e82e4 100644 --- a/src/plugins/data/public/search/aggs/agg_config.ts +++ b/src/plugins/data/public/search/aggs/agg_config.ts @@ -19,7 +19,7 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { Assign } from '@kbn/utility-types'; +import { Assign, Ensure } from '@kbn/utility-types'; import { ExpressionAstFunction, ExpressionAstArgument } from 'src/plugins/expressions/public'; import { IAggType } from './agg_type'; import { writeParams } from './agg_params'; @@ -31,17 +31,22 @@ import { FieldFormatsStart } from '../../field_formats'; type State = string | number | boolean | null | undefined | SerializableState; -interface SerializableState { +/** @internal **/ +export interface SerializableState { [key: string]: State | State[]; } -export interface AggConfigSerialized { - type: string; - enabled?: boolean; - id?: string; - params?: SerializableState; - schema?: string; -} +/** @internal **/ +export type AggConfigSerialized = Ensure< + { + type: string; + enabled?: boolean; + id?: string; + params?: SerializableState; + schema?: string; + }, + SerializableState +>; export interface AggConfigDependencies { fieldFormats: FieldFormatsStart; diff --git a/src/plugins/data/public/search/aggs/agg_types.ts b/src/plugins/data/public/search/aggs/agg_types.ts index fec8b7a8ce420..2af29d3600246 100644 --- a/src/plugins/data/public/search/aggs/agg_types.ts +++ b/src/plugins/data/public/search/aggs/agg_types.ts @@ -105,7 +105,20 @@ export const getAggTypes = ({ ], }); +/** Buckets: **/ +import { aggFilter } from './buckets/filter_fn'; +import { aggFilters } from './buckets/filters_fn'; +import { aggSignificantTerms } from './buckets/significant_terms_fn'; +import { aggIpRange } from './buckets/ip_range_fn'; +import { aggDateRange } from './buckets/date_range_fn'; +import { aggRange } from './buckets/range_fn'; +import { aggGeoTile } from './buckets/geo_tile_fn'; +import { aggGeoHash } from './buckets/geo_hash_fn'; +import { aggHistogram } from './buckets/histogram_fn'; +import { aggDateHistogram } from './buckets/date_histogram_fn'; import { aggTerms } from './buckets/terms_fn'; + +/** Metrics: **/ import { aggAvg } from './metrics/avg_fn'; import { aggBucketAvg } from './metrics/bucket_avg_fn'; import { aggBucketMax } from './metrics/bucket_max_fn'; @@ -129,7 +142,6 @@ import { aggSum } from './metrics/sum_fn'; import { aggTopHit } from './metrics/top_hit_fn'; export const getAggTypesFunctions = () => [ - aggTerms, aggAvg, aggBucketAvg, aggBucketMax, @@ -151,4 +163,15 @@ export const getAggTypesFunctions = () => [ aggStdDeviation, aggSum, aggTopHit, + aggFilter, + aggFilters, + aggSignificantTerms, + aggIpRange, + aggDateRange, + aggRange, + aggGeoTile, + aggGeoHash, + aggDateHistogram, + aggHistogram, + aggTerms, ]; diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts index 3ecdc17cb57f3..219bb5440c8da 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_histogram.ts @@ -27,7 +27,7 @@ import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterDateHistogram } from './create_filter/date_histogram'; import { intervalOptions } from './_interval_options'; -import { dateHistogramInterval } from '../../../../common'; +import { dateHistogramInterval, TimeRange } from '../../../../common'; import { writeParams } from '../agg_params'; import { isMetricAggType } from '../metrics/metric_agg_type'; @@ -35,6 +35,8 @@ import { FIELD_FORMAT_IDS, KBN_FIELD_TYPES } from '../../../../common'; import { TimefilterContract } from '../../../query'; import { QuerySetup } from '../../../query/query_service'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; +import { ExtendedBounds } from './lib/extended_bounds'; const detectedTimezone = moment.tz.guess(); const tzOffset = moment().format('Z'); @@ -67,6 +69,19 @@ export function isDateHistogramBucketAggConfig(agg: any): agg is IBucketDateHist return Boolean(agg.buckets); } +export interface AggParamsDateHistogram extends BaseAggParams { + field?: string; + timeRange?: TimeRange; + useNormalizedEsInterval?: boolean; + scaleMetricValues?: boolean; + interval?: string; + time_zone?: string; + drop_partials?: boolean; + format?: string; + min_doc_count?: number; + extended_bounds?: ExtendedBounds; +} + export const getDateHistogramBucketAgg = ({ uiSettings, query, @@ -89,6 +104,7 @@ export const getDateHistogramBucketAgg = ({ } const field = agg.getFieldDisplayName(); + return i18n.translate('data.search.aggs.buckets.dateHistogramLabel', { defaultMessage: '{fieldName} per {intervalDescription}', values: { diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.test.ts new file mode 100644 index 0000000000000..bd3c4f8dd58cf --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.test.ts @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggDateHistogram } from './date_histogram_fn'; + +describe('agg_expression_functions', () => { + describe('aggDateHistogram', () => { + const fn = functionWrapper(aggDateHistogram()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({}); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "drop_partials": undefined, + "extended_bounds": undefined, + "field": undefined, + "format": undefined, + "interval": undefined, + "json": undefined, + "min_doc_count": undefined, + "scaleMetricValues": undefined, + "timeRange": undefined, + "time_zone": undefined, + "useNormalizedEsInterval": undefined, + }, + "schema": undefined, + "type": "date_histogram", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'field', + timeRange: JSON.stringify({ + from: 'from', + to: 'to', + }), + useNormalizedEsInterval: true, + scaleMetricValues: true, + interval: 'interval', + time_zone: 'time_zone', + drop_partials: false, + format: 'format', + min_doc_count: 1, + extended_bounds: JSON.stringify({ + min: 1, + max: 2, + }), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "drop_partials": false, + "extended_bounds": Object { + "max": 2, + "min": 1, + }, + "field": "field", + "format": "format", + "interval": "interval", + "json": undefined, + "min_doc_count": 1, + "scaleMetricValues": true, + "timeRange": Object { + "from": "from", + "to": "to", + }, + "time_zone": "time_zone", + "useNormalizedEsInterval": true, + }, + "schema": undefined, + "type": "date_histogram", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.ts b/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.ts new file mode 100644 index 0000000000000..033b44da0880f --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/date_histogram_fn.ts @@ -0,0 +1,155 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggDateHistogram'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggDateHistogram = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.dateHistogram.help', { + defaultMessage: 'Generates a serialized agg config for a Histogram agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.dateHistogram.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + useNormalizedEsInterval: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.useNormalizedEsInterval.help', { + defaultMessage: 'Specifies whether to use useNormalizedEsInterval for this aggregation', + }), + }, + time_zone: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.timeZone.help', { + defaultMessage: 'Time zone to use for this aggregation', + }), + }, + format: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.format.help', { + defaultMessage: 'Format to use for this aggregation', + }), + }, + scaleMetricValues: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.scaleMetricValues.help', { + defaultMessage: 'Specifies whether to use scaleMetricValues for this aggregation', + }), + }, + interval: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.interval.help', { + defaultMessage: 'Interval to use for this aggregation', + }), + }, + timeRange: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.timeRange.help', { + defaultMessage: 'Time Range to use for this aggregation', + }), + }, + min_doc_count: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.minDocCount.help', { + defaultMessage: 'Minimum document count to use for this aggregation', + }), + }, + drop_partials: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.dropPartials.help', { + defaultMessage: 'Specifies whether to use drop_partials for this aggregation', + }), + }, + extended_bounds: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.extendedBounds.help', { + defaultMessage: + 'With extended_bounds setting, you now can "force" the histogram aggregation to start building buckets on a specific min value and also keep on building buckets up to a max value ', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateHistogram.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.DATE_HISTOGRAM, + params: { + ...rest, + timeRange: getParsedValue(args, 'timeRange'), + extended_bounds: getParsedValue(args, 'extended_bounds'), + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/date_range.ts b/src/plugins/data/public/search/aggs/buckets/date_range.ts index 07d927e64a943..504958854cad4 100644 --- a/src/plugins/data/public/search/aggs/buckets/date_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/date_range.ts @@ -29,6 +29,7 @@ import { convertDateRangeToString, DateRangeKey } from './lib/date_range'; import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; const dateRangeTitle = i18n.translate('data.search.aggs.buckets.dateRangeTitle', { defaultMessage: 'Date Range', @@ -39,6 +40,12 @@ export interface DateRangeBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsDateRange extends BaseAggParams { + field?: string; + ranges?: DateRangeKey[]; + time_zone?: string; +} + export const getDateRangeBucketAgg = ({ uiSettings, getInternalStartServices, diff --git a/src/plugins/data/public/search/aggs/buckets/date_range_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/date_range_fn.test.ts new file mode 100644 index 0000000000000..93bb791874e67 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/date_range_fn.test.ts @@ -0,0 +1,101 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggDateRange } from './date_range_fn'; + +describe('agg_expression_functions', () => { + describe('aggDateRange', () => { + const fn = functionWrapper(aggDateRange()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({}); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": undefined, + "json": undefined, + "ranges": undefined, + "time_zone": undefined, + }, + "schema": undefined, + "type": "date_range", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'date_field', + time_zone: 'UTC +3', + ranges: JSON.stringify([ + { from: 'now-1w/w', to: 'now' }, + { from: 1588163532470, to: 1588163532481 }, + ]), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "date_field", + "json": undefined, + "ranges": Array [ + Object { + "from": "now-1w/w", + "to": "now", + }, + Object { + "from": 1588163532470, + "to": 1588163532481, + }, + ], + "time_zone": "UTC +3", + }, + "schema": undefined, + "type": "date_range", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'date_field', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'date_field', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/date_range_fn.ts b/src/plugins/data/public/search/aggs/buckets/date_range_fn.ts new file mode 100644 index 0000000000000..1fe42ce63d815 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/date_range_fn.ts @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggDateRange'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggDateRange = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.dateRange.help', { + defaultMessage: 'Generates a serialized agg config for a Date Range agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.dateRange.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + ranges: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.ranges.help', { + defaultMessage: 'Serialized ranges to use for this aggregation.', + }), + }, + time_zone: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.timeZone.help', { + defaultMessage: 'Time zone to use for this aggregation.', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.dateRange.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.DATE_RANGE, + params: { + ...rest, + json: getParsedValue(args, 'json'), + ranges: getParsedValue(args, 'ranges'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/filter.ts b/src/plugins/data/public/search/aggs/buckets/filter.ts index accbdf4dd783d..69157edad4f68 100644 --- a/src/plugins/data/public/search/aggs/buckets/filter.ts +++ b/src/plugins/data/public/search/aggs/buckets/filter.ts @@ -21,6 +21,8 @@ import { i18n } from '@kbn/i18n'; import { BucketAggType } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { GetInternalStartServicesFn } from '../../../types'; +import { GeoBoundingBox } from './lib/geo_point'; +import { BaseAggParams } from '../types'; const filterTitle = i18n.translate('data.search.aggs.buckets.filterTitle', { defaultMessage: 'Filter', @@ -30,6 +32,10 @@ export interface FilterBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsFilter extends BaseAggParams { + geo_bounding_box?: GeoBoundingBox; +} + export const getFilterBucketAgg = ({ getInternalStartServices }: FilterBucketAggDependencies) => new BucketAggType( { diff --git a/src/plugins/data/public/search/aggs/buckets/filter_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/filter_fn.test.ts new file mode 100644 index 0000000000000..c820a73b0a894 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filter_fn.test.ts @@ -0,0 +1,85 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggFilter } from './filter_fn'; + +describe('agg_expression_functions', () => { + describe('aggFilter', () => { + const fn = functionWrapper(aggFilter()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({}); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "geo_bounding_box": undefined, + "json": undefined, + }, + "schema": undefined, + "type": "filter", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + geo_bounding_box: JSON.stringify({ + wkt: 'BBOX (-74.1, -71.12, 40.73, 40.01)', + }), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "geo_bounding_box": Object { + "wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)", + }, + "json": undefined, + }, + "schema": undefined, + "type": "filter", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/filter_fn.ts b/src/plugins/data/public/search/aggs/buckets/filter_fn.ts new file mode 100644 index 0000000000000..4a7180fc86c71 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filter_fn.ts @@ -0,0 +1,99 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggFilter'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggFilter = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.filter.help', { + defaultMessage: 'Generates a serialized agg config for a Filter agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filter.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.filter.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filter.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + geo_bounding_box: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filter.geoBoundingBox.help', { + defaultMessage: 'Filter results based on a point location within a bounding box', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filter.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filter.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.FILTER, + params: { + ...rest, + json: getParsedValue(args, 'json'), + geo_bounding_box: getParsedValue(args, 'geo_bounding_box'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/filters.ts b/src/plugins/data/public/search/aggs/buckets/filters.ts index fe013928bba65..c993c0fc13800 100644 --- a/src/plugins/data/public/search/aggs/buckets/filters.ts +++ b/src/plugins/data/public/search/aggs/buckets/filters.ts @@ -29,6 +29,7 @@ import { Storage } from '../../../../../../plugins/kibana_utils/public'; import { getEsQueryConfig, buildEsQuery, Query } from '../../../../common'; import { getQueryLog } from '../../../query'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; const filtersTitle = i18n.translate('data.search.aggs.buckets.filtersTitle', { defaultMessage: 'Filters', @@ -47,6 +48,13 @@ export interface FiltersBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsFilters extends BaseAggParams { + filters?: Array<{ + input: Query; + label: string; + }>; +} + export const getFiltersBucketAgg = ({ uiSettings, getInternalStartServices, diff --git a/src/plugins/data/public/search/aggs/buckets/filters_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/filters_fn.test.ts new file mode 100644 index 0000000000000..99c4f7d8c2b65 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filters_fn.test.ts @@ -0,0 +1,91 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggFilters } from './filters_fn'; + +describe('agg_expression_functions', () => { + describe('aggFilters', () => { + const fn = functionWrapper(aggFilters()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({}); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "filters": undefined, + "json": undefined, + }, + "schema": undefined, + "type": "filters", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + filters: JSON.stringify([ + { + query: 'query', + language: 'lucene', + label: 'test', + }, + ]), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "filters": Array [ + Object { + "label": "test", + "language": "lucene", + "query": "query", + }, + ], + "json": undefined, + }, + "schema": undefined, + "type": "filters", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/filters_fn.ts b/src/plugins/data/public/search/aggs/buckets/filters_fn.ts new file mode 100644 index 0000000000000..6ffd5369d7087 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/filters_fn.ts @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggFilters'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggFilters = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.filters.help', { + defaultMessage: 'Generates a serialized agg config for a Filter agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filters.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.filters.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filters.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + filters: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filters.filters.help', { + defaultMessage: 'Filters to use for this aggregation', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.filters.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.FILTERS, + params: { + ...rest, + filters: getParsedValue(args, 'filters'), + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts index eab10edad60f6..be339de5d7fae 100644 --- a/src/plugins/data/public/search/aggs/buckets/geo_hash.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash.ts @@ -22,6 +22,8 @@ import { BucketAggType, IBucketAggConfig } from './bucket_agg_type'; import { KBN_FIELD_TYPES } from '../../../../common'; import { BUCKET_TYPES } from './bucket_agg_types'; import { GetInternalStartServicesFn } from '../../../types'; +import { GeoBoundingBox } from './lib/geo_point'; +import { BaseAggParams } from '../types'; const defaultBoundingBox = { top_left: { lat: 1, lon: 1 }, @@ -38,6 +40,15 @@ export interface GeoHashBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsGeoHash extends BaseAggParams { + field: string; + autoPrecision?: boolean; + precision?: number; + useGeocentroid?: boolean; + isFilteredByCollar?: boolean; + boundingBox?: GeoBoundingBox; +} + export const getGeoHashBucketAgg = ({ getInternalStartServices }: GeoHashBucketAggDependencies) => new BucketAggType( { diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.test.ts new file mode 100644 index 0000000000000..07ab8e66f1def --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.test.ts @@ -0,0 +1,112 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggGeoHash } from './geo_hash_fn'; + +describe('agg_expression_functions', () => { + describe('aggGeoHash', () => { + const fn = functionWrapper(aggGeoHash()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'geo_field', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "autoPrecision": undefined, + "boundingBox": undefined, + "customLabel": undefined, + "field": "geo_field", + "isFilteredByCollar": undefined, + "json": undefined, + "precision": undefined, + "useGeocentroid": undefined, + }, + "schema": undefined, + "type": "geohash_grid", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'geo_field', + autoPrecision: false, + precision: 10, + useGeocentroid: true, + isFilteredByCollar: false, + boundingBox: JSON.stringify({ + top_left: [-74.1, 40.73], + bottom_right: [-71.12, 40.01], + }), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "autoPrecision": false, + "boundingBox": Object { + "bottom_right": Array [ + -71.12, + 40.01, + ], + "top_left": Array [ + -74.1, + 40.73, + ], + }, + "customLabel": undefined, + "field": "geo_field", + "isFilteredByCollar": false, + "json": undefined, + "precision": 10, + "useGeocentroid": true, + }, + "schema": undefined, + "type": "geohash_grid", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'geo_field', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'geo_field', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.ts b/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.ts new file mode 100644 index 0000000000000..bbfa8575d486c --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/geo_hash_fn.ts @@ -0,0 +1,129 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggGeoHash'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggGeoHash = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.geoHash.help', { + defaultMessage: 'Generates a serialized agg config for a Geo Hash agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoHash.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.geoHash.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoHash.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.geoHash.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + useGeocentroid: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.geoHash.useGeocentroid.help', { + defaultMessage: 'Specifies whether to use geocentroid for this aggregation', + }), + }, + autoPrecision: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.geoHash.autoPrecision.help', { + defaultMessage: 'Specifies whether to use auto precision for this aggregation', + }), + }, + isFilteredByCollar: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.geoHash.isFilteredByCollar.help', { + defaultMessage: 'Specifies whether to filter by collar', + }), + }, + boundingBox: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoHash.boundingBox.help', { + defaultMessage: 'Filter results based on a point location within a bounding box', + }), + }, + precision: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.geoHash.precision.help', { + defaultMessage: 'Precision to use for this aggregation.', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoHash.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoHash.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.GEOHASH_GRID, + params: { + ...rest, + boundingBox: getParsedValue(args, 'boundingBox'), + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile.ts b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts index c981e8400f9a1..1212bba23a93a 100644 --- a/src/plugins/data/public/search/aggs/buckets/geo_tile.ts +++ b/src/plugins/data/public/search/aggs/buckets/geo_tile.ts @@ -25,6 +25,7 @@ import { BUCKET_TYPES } from './bucket_agg_types'; import { KBN_FIELD_TYPES } from '../../../../common'; import { METRIC_TYPES } from '../metrics/metric_agg_types'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; export interface GeoTitleBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; @@ -34,6 +35,12 @@ const geotileGridTitle = i18n.translate('data.search.aggs.buckets.geotileGridTit defaultMessage: 'Geotile', }); +export interface AggParamsGeoTile extends BaseAggParams { + field: string; + useGeocentroid?: boolean; + precision?: number; +} + export const getGeoTitleBucketAgg = ({ getInternalStartServices }: GeoTitleBucketAggDependencies) => new BucketAggType( { diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.test.ts new file mode 100644 index 0000000000000..bfaf47ede8734 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.test.ts @@ -0,0 +1,91 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggGeoTile } from './geo_tile_fn'; + +describe('agg_expression_functions', () => { + describe('aggGeoTile', () => { + const fn = functionWrapper(aggGeoTile()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'geo_field', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "geo_field", + "json": undefined, + "precision": undefined, + "useGeocentroid": undefined, + }, + "schema": undefined, + "type": "geotile_grid", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'geo_field', + useGeocentroid: false, + precision: 10, + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "geo_field", + "json": undefined, + "precision": 10, + "useGeocentroid": false, + }, + "schema": undefined, + "type": "geotile_grid", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'geo_field', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'geo_field', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.ts b/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.ts new file mode 100644 index 0000000000000..9c33ef45762af --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/geo_tile_fn.ts @@ -0,0 +1,108 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggGeoTile'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggGeoTile = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.geoTile.help', { + defaultMessage: 'Generates a serialized agg config for a Geo Tile agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoTile.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.geoTile.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoTile.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.geoTile.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + useGeocentroid: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.geoTile.useGeocentroid.help', { + defaultMessage: 'Specifies whether to use geocentroid for this aggregation', + }), + }, + precision: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.geoTile.precision.help', { + defaultMessage: 'Precision to use for this aggregation.', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoTile.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.geoTile.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.GEOTILE_GRID, + params: { + ...rest, + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/histogram.ts b/src/plugins/data/public/search/aggs/buckets/histogram.ts index f8e8720d24ea9..d04df4f8aac6b 100644 --- a/src/plugins/data/public/search/aggs/buckets/histogram.ts +++ b/src/plugins/data/public/search/aggs/buckets/histogram.ts @@ -26,6 +26,8 @@ import { createFilterHistogram } from './create_filter/histogram'; import { BUCKET_TYPES } from './bucket_agg_types'; import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; +import { ExtendedBounds } from './lib/extended_bounds'; export interface AutoBounds { min: number; @@ -42,6 +44,15 @@ export interface IBucketHistogramAggConfig extends IBucketAggConfig { getAutoBounds: () => AutoBounds; } +export interface AggParamsHistogram extends BaseAggParams { + field: string; + interval: string; + intervalBase?: number; + min_doc_count?: boolean; + has_extended_bounds?: boolean; + extended_bounds?: ExtendedBounds; +} + export const getHistogramBucketAgg = ({ uiSettings, getInternalStartServices, diff --git a/src/plugins/data/public/search/aggs/buckets/histogram_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/histogram_fn.test.ts new file mode 100644 index 0000000000000..34b6fa1a6dcd6 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/histogram_fn.test.ts @@ -0,0 +1,109 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggHistogram } from './histogram_fn'; + +describe('agg_expression_functions', () => { + describe('aggHistogram', () => { + const fn = functionWrapper(aggHistogram()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'field', + interval: '10', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "extended_bounds": undefined, + "field": "field", + "has_extended_bounds": undefined, + "interval": "10", + "intervalBase": undefined, + "json": undefined, + "min_doc_count": undefined, + }, + "schema": undefined, + "type": "histogram", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'field', + interval: '10', + intervalBase: 1, + min_doc_count: false, + has_extended_bounds: false, + extended_bounds: JSON.stringify({ + min: 1, + max: 2, + }), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "extended_bounds": Object { + "max": 2, + "min": 1, + }, + "field": "field", + "has_extended_bounds": false, + "interval": "10", + "intervalBase": 1, + "json": undefined, + "min_doc_count": false, + }, + "schema": undefined, + "type": "histogram", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'field', + interval: '10', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'field', + interval: '10', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/histogram_fn.ts b/src/plugins/data/public/search/aggs/buckets/histogram_fn.ts new file mode 100644 index 0000000000000..1e5a5a72c0ecb --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/histogram_fn.ts @@ -0,0 +1,132 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggHistogram'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggHistogram = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.histogram.help', { + defaultMessage: 'Generates a serialized agg config for a Histogram agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.histogram.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.histogram.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.histogram.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.histogram.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + interval: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.histogram.interval.help', { + defaultMessage: 'Interval to use for this aggregation', + }), + }, + intervalBase: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.histogram.intervalBase.help', { + defaultMessage: 'IntervalBase to use for this aggregation', + }), + }, + min_doc_count: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.histogram.minDocCount.help', { + defaultMessage: 'Specifies whether to use min_doc_count for this aggregation', + }), + }, + has_extended_bounds: { + types: ['boolean'], + help: i18n.translate('data.search.aggs.buckets.histogram.hasExtendedBounds.help', { + defaultMessage: 'Specifies whether to use has_extended_bounds for this aggregation', + }), + }, + extended_bounds: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.histogram.extendedBounds.help', { + defaultMessage: + 'With extended_bounds setting, you now can "force" the histogram aggregation to start building buckets on a specific min value and also keep on building buckets up to a max value ', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.histogram.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.histogram.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.HISTOGRAM, + params: { + ...rest, + extended_bounds: getParsedValue(args, 'extended_bounds'), + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/index.ts b/src/plugins/data/public/search/aggs/buckets/index.ts index 3a402b1498a77..7036cc7785db7 100644 --- a/src/plugins/data/public/search/aggs/buckets/index.ts +++ b/src/plugins/data/public/search/aggs/buckets/index.ts @@ -19,11 +19,18 @@ export * from './_interval_options'; export * from './bucket_agg_types'; +export * from './histogram'; export * from './date_histogram'; export * from './date_range'; +export * from './range'; +export * from './filter'; +export * from './filters'; +export * from './geo_tile'; +export * from './geo_hash'; export * from './ip_range'; export * from './lib/cidr_mask'; export * from './lib/date_range'; export * from './lib/ip_range'; export * from './migrate_include_exclude_format'; +export * from './significant_terms'; export * from './terms'; diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/ip_range.ts index bde347d6e673d..029fd864154be 100644 --- a/src/plugins/data/public/search/aggs/buckets/ip_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/ip_range.ts @@ -23,18 +23,38 @@ import { BucketAggType } from './bucket_agg_type'; import { BUCKET_TYPES } from './bucket_agg_types'; import { createFilterIpRange } from './create_filter/ip_range'; -import { IpRangeKey, convertIPRangeToString } from './lib/ip_range'; +import { + convertIPRangeToString, + IpRangeKey, + RangeIpRangeAggKey, + CidrMaskIpRangeAggKey, +} from './lib/ip_range'; import { KBN_FIELD_TYPES, FieldFormat, TEXT_CONTEXT_TYPE } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; const ipRangeTitle = i18n.translate('data.search.aggs.buckets.ipRangeTitle', { defaultMessage: 'IPv4 Range', }); +export enum IP_RANGE_TYPES { + FROM_TO = 'fromTo', + MASK = 'mask', +} + export interface IpRangeBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsIpRange extends BaseAggParams { + field: string; + ipRangeType?: IP_RANGE_TYPES; + ranges?: Partial<{ + [IP_RANGE_TYPES.FROM_TO]: RangeIpRangeAggKey[]; + [IP_RANGE_TYPES.MASK]: CidrMaskIpRangeAggKey[]; + }>; +} + export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketAggDependencies) => new BucketAggType( { @@ -42,7 +62,7 @@ export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketA title: ipRangeTitle, createFilter: createFilterIpRange, getKey(bucket, key, agg): IpRangeKey { - if (agg.params.ipRangeType === 'mask') { + if (agg.params.ipRangeType === IP_RANGE_TYPES.MASK) { return { type: 'mask', mask: key }; } return { type: 'range', from: bucket.from, to: bucket.to }; @@ -74,7 +94,7 @@ export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketA }, { name: 'ipRangeType', - default: 'fromTo', + default: IP_RANGE_TYPES.FROM_TO, write: noop, }, { @@ -90,7 +110,7 @@ export const getIpRangeBucketAgg = ({ getInternalStartServices }: IpRangeBucketA const ipRangeType = aggConfig.params.ipRangeType; let ranges = aggConfig.params.ranges[ipRangeType]; - if (ipRangeType === 'fromTo') { + if (ipRangeType === IP_RANGE_TYPES.FROM_TO) { ranges = map(ranges, (range: any) => omit(range, isNull)); } diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/ip_range_fn.test.ts new file mode 100644 index 0000000000000..5940345b25890 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/ip_range_fn.test.ts @@ -0,0 +1,102 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { IP_RANGE_TYPES } from './ip_range'; +import { aggIpRange } from './ip_range_fn'; + +describe('agg_expression_functions', () => { + describe('aggIpRange', () => { + const fn = functionWrapper(aggIpRange()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'ip_field', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "ip_field", + "ipRangeType": undefined, + "json": undefined, + "ranges": undefined, + }, + "schema": undefined, + "type": "ip_range", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'ip_field', + ipRangeType: IP_RANGE_TYPES.MASK, + ranges: JSON.stringify({ + mask: [{ mask: '10.0.0.0/25' }], + }), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "ip_field", + "ipRangeType": "mask", + "json": undefined, + "ranges": Object { + "mask": Array [ + Object { + "mask": "10.0.0.0/25", + }, + ], + }, + }, + "schema": undefined, + "type": "ip_range", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'ip_field', + ipRangeType: IP_RANGE_TYPES.MASK, + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'ip_field', + ipRangeType: IP_RANGE_TYPES.FROM_TO, + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/ip_range_fn.ts b/src/plugins/data/public/search/aggs/buckets/ip_range_fn.ts new file mode 100644 index 0000000000000..554a8708d9164 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/ip_range_fn.ts @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggIpRange'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggIpRange = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.ipRange.help', { + defaultMessage: 'Generates a serialized agg config for a Ip Range agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipRange.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.ipRange.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipRange.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.ipRange.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + ipRangeType: { + types: ['string'], + options: ['mask', 'fromTo'], + help: i18n.translate('data.search.aggs.buckets.ipRange.ipRangeType.help', { + defaultMessage: + 'IP range type to use for this aggregation. Takes one of the following values: mask, fromTo.', + }), + }, + ranges: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipRange.ranges.help', { + defaultMessage: 'Serialized ranges to use for this aggregation.', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipRange.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.ipRange.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.IP_RANGE, + params: { + ...rest, + json: getParsedValue(args, 'json'), + ranges: getParsedValue(args, 'ranges'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts b/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts index 6eb9fe8414ec8..d52bdff993a2b 100644 --- a/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/lib/date_range.ts @@ -18,8 +18,8 @@ */ export interface DateRangeKey { - from: number; - to: number; + from: number | string; + to: number | string; } export function convertDateRangeToString({ from, to }: DateRangeKey, format: (val: any) => string) { diff --git a/src/plugins/discover/public/helpers/shorten_dotted_string.ts b/src/plugins/data/public/search/aggs/buckets/lib/extended_bounds.ts similarity index 79% rename from src/plugins/discover/public/helpers/shorten_dotted_string.ts rename to src/plugins/data/public/search/aggs/buckets/lib/extended_bounds.ts index 9d78a96784339..7a249a9daca91 100644 --- a/src/plugins/discover/public/helpers/shorten_dotted_string.ts +++ b/src/plugins/data/public/search/aggs/buckets/lib/extended_bounds.ts @@ -17,10 +17,7 @@ * under the License. */ -const DOT_PREFIX_RE = /(.).+?\./g; - -/** - * Convert a dot.notated.string into a short - * version (d.n.string) - */ -export const shortenDottedString = (input: string) => input.replace(DOT_PREFIX_RE, '$1.'); +export interface ExtendedBounds { + min: number; + max: number; +} diff --git a/src/plugins/data/public/search/aggs/buckets/lib/geo_point.ts b/src/plugins/data/public/search/aggs/buckets/lib/geo_point.ts new file mode 100644 index 0000000000000..8ff4493e286cf --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/lib/geo_point.ts @@ -0,0 +1,86 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +type GeoPoint = + | { + lat: number; + lon: number; + } + | string + | [number, number]; + +interface GeoBox { + top: number; + left: number; + bottom: number; + right: number; +} + +/** GeoBoundingBox Accepted Formats: + * Lat Lon As Properties: + * "top_left" : { + * "lat" : 40.73, "lon" : -74.1 + * }, + * "bottom_right" : { + * "lat" : 40.01, "lon" : -71.12 + * } + * + * Lat Lon As Array: + * { + * "top_left" : [-74.1, 40.73], + * "bottom_right" : [-71.12, 40.01] + * } + * + * Lat Lon As String: + * { + * "top_left" : "40.73, -74.1", + * "bottom_right" : "40.01, -71.12" + * } + * + * Bounding Box as Well-Known Text (WKT): + * { + * "wkt" : "BBOX (-74.1, -71.12, 40.73, 40.01)" + * } + * + * Geohash: + * { + * "top_right" : "dr5r9ydj2y73", + * "bottom_left" : "drj7teegpus6" + * } + * + * Vertices: + * { + * "top" : 40.73, + * "left" : -74.1, + * "bottom" : 40.01, + * "right" : -71.12 + * } + * + * **/ +export type GeoBoundingBox = + | Partial<{ + top_left: GeoPoint; + top_right: GeoPoint; + bottom_right: GeoPoint; + bottom_left: GeoPoint; + }> + | { + wkt: string; + } + | GeoBox; diff --git a/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts b/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts index be1ac28934c7c..57e5337d4c365 100644 --- a/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts +++ b/src/plugins/data/public/search/aggs/buckets/lib/ip_range.ts @@ -17,9 +17,18 @@ * under the License. */ -export type IpRangeKey = - | { type: 'mask'; mask: string } - | { type: 'range'; from: string; to: string }; +export interface CidrMaskIpRangeAggKey { + type: 'mask'; + mask: string; +} + +export interface RangeIpRangeAggKey { + type: 'range'; + from: string; + to: string; +} + +export type IpRangeKey = CidrMaskIpRangeAggKey | RangeIpRangeAggKey; export const convertIPRangeToString = (range: IpRangeKey, format: (val: any) => string) => { if (range.type === 'mask') { diff --git a/src/plugins/data/public/search/aggs/buckets/range.ts b/src/plugins/data/public/search/aggs/buckets/range.ts index 2c1303814a88a..02aad3bd5fed1 100644 --- a/src/plugins/data/public/search/aggs/buckets/range.ts +++ b/src/plugins/data/public/search/aggs/buckets/range.ts @@ -24,6 +24,7 @@ import { RangeKey } from './range_key'; import { createFilterRange } from './create_filter/range'; import { BUCKET_TYPES } from './bucket_agg_types'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; const keyCaches = new WeakMap(); const formats = new WeakMap(); @@ -36,6 +37,14 @@ export interface RangeBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsRange extends BaseAggParams { + field: string; + ranges?: Array<{ + from: number; + to: number; + }>; +} + export const getRangeBucketAgg = ({ getInternalStartServices }: RangeBucketAggDependencies) => new BucketAggType( { diff --git a/src/plugins/data/public/search/aggs/buckets/range_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/range_fn.test.ts new file mode 100644 index 0000000000000..93ae4490196a8 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/range_fn.test.ts @@ -0,0 +1,100 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggRange } from './range_fn'; + +describe('agg_expression_functions', () => { + describe('aggRange', () => { + const fn = functionWrapper(aggRange()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'number_field', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "number_field", + "json": undefined, + "ranges": undefined, + }, + "schema": undefined, + "type": "range", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + field: 'number_field', + ranges: JSON.stringify([ + { from: 1, to: 2 }, + { from: 5, to: 100 }, + ]), + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "field": "number_field", + "json": undefined, + "ranges": Array [ + Object { + "from": 1, + "to": 2, + }, + Object { + "from": 5, + "to": 100, + }, + ], + }, + "schema": undefined, + "type": "range", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'number_field', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + + expect(() => { + fn({ + field: 'number_field', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/range_fn.ts b/src/plugins/data/public/search/aggs/buckets/range_fn.ts new file mode 100644 index 0000000000000..48686e7061de9 --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/range_fn.ts @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { Assign } from '@kbn/utility-types'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggRange'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = Assign; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggRange = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.range.help', { + defaultMessage: 'Generates a serialized agg config for a Range agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.range.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.range.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.range.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.range.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + ranges: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.range.ranges.help', { + defaultMessage: 'Serialized ranges to use for this aggregation.', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.range.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.range.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.RANGE, + params: { + ...rest, + json: getParsedValue(args, 'json'), + ranges: getParsedValue(args, 'ranges'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts index 49d797f3afbc9..e6afc56dfd31c 100644 --- a/src/plugins/data/public/search/aggs/buckets/significant_terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/significant_terms.ts @@ -24,6 +24,7 @@ import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exc import { BUCKET_TYPES } from './bucket_agg_types'; import { KBN_FIELD_TYPES } from '../../../../common'; import { GetInternalStartServicesFn } from '../../../types'; +import { BaseAggParams } from '../types'; const significantTermsTitle = i18n.translate('data.search.aggs.buckets.significantTermsTitle', { defaultMessage: 'Significant Terms', @@ -33,6 +34,13 @@ export interface SignificantTermsBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } +export interface AggParamsSignificantTerms extends BaseAggParams { + field: string; + size?: number; + exclude?: string; + include?: string; +} + export const getSignificantTermsBucketAgg = ({ getInternalStartServices, }: SignificantTermsBucketAggDependencies) => diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.test.ts new file mode 100644 index 0000000000000..71be4e9cfa9ac --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.test.ts @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { functionWrapper } from '../test_helpers'; +import { aggSignificantTerms } from './significant_terms_fn'; + +describe('agg_expression_functions', () => { + describe('aggSignificantTerms', () => { + const fn = functionWrapper(aggSignificantTerms()); + + test('fills in defaults when only required args are provided', () => { + const actual = fn({ + field: 'machine.os.keyword', + }); + expect(actual).toMatchInlineSnapshot(` + Object { + "type": "agg_type", + "value": Object { + "enabled": true, + "id": undefined, + "params": Object { + "customLabel": undefined, + "exclude": undefined, + "field": "machine.os.keyword", + "include": undefined, + "json": undefined, + "size": undefined, + }, + "schema": undefined, + "type": "significant_terms", + }, + } + `); + }); + + test('includes optional params when they are provided', () => { + const actual = fn({ + id: '1', + enabled: false, + schema: 'whatever', + field: 'machine.os.keyword', + size: 6, + include: 'win', + exclude: 'ios', + }); + + expect(actual.value).toMatchInlineSnapshot(` + Object { + "enabled": false, + "id": "1", + "params": Object { + "customLabel": undefined, + "exclude": "ios", + "field": "machine.os.keyword", + "include": "win", + "json": undefined, + "size": 6, + }, + "schema": "whatever", + "type": "significant_terms", + } + `); + }); + + test('correctly parses json string argument', () => { + const actual = fn({ + field: 'machine.os.keyword', + json: '{ "foo": true }', + }); + + expect(actual.value.params.json).toEqual({ foo: true }); + expect(() => { + fn({ + field: 'machine.os.keyword', + json: '/// intentionally malformed json ///', + }); + }).toThrowErrorMatchingInlineSnapshot(`"Unable to parse json argument string"`); + }); + }); +}); diff --git a/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.ts b/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.ts new file mode 100644 index 0000000000000..83583070bddfe --- /dev/null +++ b/src/plugins/data/public/search/aggs/buckets/significant_terms_fn.ts @@ -0,0 +1,116 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { i18n } from '@kbn/i18n'; +import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; + +const fnName = 'aggSignificantTerms'; + +type Input = any; +type AggArgs = AggExpressionFunctionArgs; + +type Arguments = AggArgs; + +type Output = AggExpressionType; +type FunctionDefinition = ExpressionFunctionDefinition; + +export const aggSignificantTerms = (): FunctionDefinition => ({ + name: fnName, + help: i18n.translate('data.search.aggs.function.buckets.significantTerms.help', { + defaultMessage: 'Generates a serialized agg config for a Significant Terms agg', + }), + type: 'agg_type', + args: { + id: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.id.help', { + defaultMessage: 'ID for this aggregation', + }), + }, + enabled: { + types: ['boolean'], + default: true, + help: i18n.translate('data.search.aggs.buckets.significantTerms.enabled.help', { + defaultMessage: 'Specifies whether this aggregation should be enabled', + }), + }, + schema: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.schema.help', { + defaultMessage: 'Schema to use for this aggregation', + }), + }, + field: { + types: ['string'], + required: true, + help: i18n.translate('data.search.aggs.buckets.significantTerms.field.help', { + defaultMessage: 'Field to use for this aggregation', + }), + }, + size: { + types: ['number'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.size.help', { + defaultMessage: 'Max number of buckets to retrieve', + }), + }, + exclude: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.exclude.help', { + defaultMessage: 'Specific bucket values to exclude from results', + }), + }, + include: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.include.help', { + defaultMessage: 'Specific bucket values to include in results', + }), + }, + json: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.json.help', { + defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', + }), + }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.significantTerms.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, + }, + fn: (input, args) => { + const { id, enabled, schema, ...rest } = args; + + return { + type: 'agg_type', + value: { + id, + enabled, + schema, + type: BUCKET_TYPES.SIGNIFICANT_TERMS, + params: { + ...rest, + json: getParsedValue(args, 'json'), + }, + }, + }; + }, +}); diff --git a/src/plugins/data/public/search/aggs/buckets/terms.ts b/src/plugins/data/public/search/aggs/buckets/terms.ts index a12a1d7ac2d3d..1bfc508dc3871 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms.ts @@ -26,7 +26,7 @@ import { isStringOrNumberType, migrateIncludeExcludeFormat, } from './migrate_include_exclude_format'; -import { AggConfigSerialized, IAggConfigs } from '../types'; +import { AggConfigSerialized, BaseAggParams, IAggConfigs } from '../types'; import { Adapters } from '../../../../../inspector/public'; import { ISearchSource } from '../../search_source'; @@ -63,11 +63,11 @@ export interface TermsBucketAggDependencies { getInternalStartServices: GetInternalStartServicesFn; } -export interface AggParamsTerms { +export interface AggParamsTerms extends BaseAggParams { field: string; - order: 'asc' | 'desc'; orderBy: string; orderAgg?: AggConfigSerialized; + order?: 'asc' | 'desc'; size?: number; missingBucket?: boolean; missingBucketLabel?: string; @@ -76,7 +76,6 @@ export interface AggParamsTerms { // advanced exclude?: string; include?: string; - json?: string; } export const getTermsBucketAgg = ({ getInternalStartServices }: TermsBucketAggDependencies) => diff --git a/src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts b/src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts index f55f1de796013..1384a9f17e4b6 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms_fn.test.ts @@ -27,7 +27,6 @@ describe('agg_expression_functions', () => { test('fills in defaults when only required args are provided', () => { const actual = fn({ field: 'machine.os.keyword', - order: 'asc', orderBy: '1', }); expect(actual).toMatchInlineSnapshot(` @@ -37,18 +36,19 @@ describe('agg_expression_functions', () => { "enabled": true, "id": undefined, "params": Object { + "customLabel": undefined, "exclude": undefined, "field": "machine.os.keyword", "include": undefined, "json": undefined, - "missingBucket": false, - "missingBucketLabel": "Missing", - "order": "asc", + "missingBucket": undefined, + "missingBucketLabel": undefined, + "order": undefined, "orderAgg": undefined, "orderBy": "1", - "otherBucket": false, - "otherBucketLabel": "Other", - "size": 5, + "otherBucket": undefined, + "otherBucketLabel": undefined, + "size": undefined, }, "schema": undefined, "type": "terms", @@ -70,6 +70,7 @@ describe('agg_expression_functions', () => { missingBucketLabel: 'missing', otherBucket: true, otherBucketLabel: 'other', + include: 'win', exclude: 'ios', }); @@ -78,9 +79,10 @@ describe('agg_expression_functions', () => { "enabled": false, "id": "1", "params": Object { + "customLabel": undefined, "exclude": "ios", "field": "machine.os.keyword", - "include": undefined, + "include": "win", "json": undefined, "missingBucket": true, "missingBucketLabel": "missing", @@ -107,37 +109,39 @@ describe('agg_expression_functions', () => { expect(actual.value.params).toMatchInlineSnapshot(` Object { + "customLabel": undefined, "exclude": undefined, "field": "machine.os.keyword", "include": undefined, "json": undefined, - "missingBucket": false, - "missingBucketLabel": "Missing", + "missingBucket": undefined, + "missingBucketLabel": undefined, "order": "asc", "orderAgg": Object { "enabled": true, "id": undefined, "params": Object { + "customLabel": undefined, "exclude": undefined, "field": "name", "include": undefined, "json": undefined, - "missingBucket": false, - "missingBucketLabel": "Missing", + "missingBucket": undefined, + "missingBucketLabel": undefined, "order": "asc", "orderAgg": undefined, "orderBy": "1", - "otherBucket": false, - "otherBucketLabel": "Other", - "size": 5, + "otherBucket": undefined, + "otherBucketLabel": undefined, + "size": undefined, }, "schema": undefined, "type": "terms", }, "orderBy": "1", - "otherBucket": false, - "otherBucketLabel": "Other", - "size": 5, + "otherBucket": undefined, + "otherBucketLabel": undefined, + "size": undefined, } `); }); diff --git a/src/plugins/data/public/search/aggs/buckets/terms_fn.ts b/src/plugins/data/public/search/aggs/buckets/terms_fn.ts index 7980bfabe79fb..49520863fe1cc 100644 --- a/src/plugins/data/public/search/aggs/buckets/terms_fn.ts +++ b/src/plugins/data/public/search/aggs/buckets/terms_fn.ts @@ -20,27 +20,25 @@ import { i18n } from '@kbn/i18n'; import { Assign } from '@kbn/utility-types'; import { ExpressionFunctionDefinition } from '../../../../../expressions/public'; -import { AggExpressionType, AggExpressionFunctionArgs } from '../'; +import { AggExpressionType, AggExpressionFunctionArgs, BUCKET_TYPES } from '../'; +import { getParsedValue } from '../utils/get_parsed_value'; -const aggName = 'terms'; const fnName = 'aggTerms'; type Input = any; -type AggArgs = AggExpressionFunctionArgs; +type AggArgs = AggExpressionFunctionArgs; + // Since the orderAgg param is an agg nested in a subexpression, we need to // overwrite the param type to expect a value of type AggExpressionType. -type Arguments = AggArgs & - Assign< - AggArgs, - { orderAgg?: AggArgs['orderAgg'] extends undefined ? undefined : AggExpressionType } - >; +type Arguments = Assign; + type Output = AggExpressionType; type FunctionDefinition = ExpressionFunctionDefinition; export const aggTerms = (): FunctionDefinition => ({ name: fnName, help: i18n.translate('data.search.aggs.function.buckets.terms.help', { - defaultMessage: 'Generates a serialized agg config for a terms agg', + defaultMessage: 'Generates a serialized agg config for a Terms agg', }), type: 'agg_type', args: { @@ -72,7 +70,7 @@ export const aggTerms = (): FunctionDefinition => ({ }, order: { types: ['string'], - required: true, + options: ['asc', 'desc'], help: i18n.translate('data.search.aggs.buckets.terms.order.help', { defaultMessage: 'Order in which to return the results: asc or desc', }), @@ -91,41 +89,30 @@ export const aggTerms = (): FunctionDefinition => ({ }, size: { types: ['number'], - default: 5, help: i18n.translate('data.search.aggs.buckets.terms.size.help', { defaultMessage: 'Max number of buckets to retrieve', }), }, missingBucket: { types: ['boolean'], - default: false, help: i18n.translate('data.search.aggs.buckets.terms.missingBucket.help', { defaultMessage: 'When set to true, groups together any buckets with missing fields', }), }, missingBucketLabel: { types: ['string'], - default: i18n.translate('data.search.aggs.buckets.terms.missingBucketLabel', { - defaultMessage: 'Missing', - description: `Default label used in charts when documents are missing a field. - Visible when you create a chart with a terms aggregation and enable "Show missing values"`, - }), help: i18n.translate('data.search.aggs.buckets.terms.missingBucketLabel.help', { defaultMessage: 'Default label used in charts when documents are missing a field.', }), }, otherBucket: { types: ['boolean'], - default: false, help: i18n.translate('data.search.aggs.buckets.terms.otherBucket.help', { defaultMessage: 'When set to true, groups together any buckets beyond the allowed size', }), }, otherBucketLabel: { types: ['string'], - default: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel', { - defaultMessage: 'Other', - }), help: i18n.translate('data.search.aggs.buckets.terms.otherBucketLabel.help', { defaultMessage: 'Default label used in charts for documents in the Other bucket', }), @@ -148,32 +135,27 @@ export const aggTerms = (): FunctionDefinition => ({ defaultMessage: 'Advanced json to include when the agg is sent to Elasticsearch', }), }, + customLabel: { + types: ['string'], + help: i18n.translate('data.search.aggs.buckets.terms.customLabel.help', { + defaultMessage: 'Represents a custom label for this aggregation', + }), + }, }, fn: (input, args) => { const { id, enabled, schema, ...rest } = args; - let json; - try { - json = args.json ? JSON.parse(args.json) : undefined; - } catch (e) { - throw new Error('Unable to parse json argument string'); - } - - // Need to spread this object to work around TS bug: - // https://github.com/microsoft/TypeScript/issues/15300#issuecomment-436793742 - const orderAgg = args.orderAgg?.value ? { ...args.orderAgg.value } : undefined; - return { type: 'agg_type', value: { id, enabled, schema, - type: aggName, + type: BUCKET_TYPES.TERMS, params: { ...rest, - orderAgg, - json, + orderAgg: args.orderAgg?.value, + json: getParsedValue(args, 'json'), }, }, }; diff --git a/src/plugins/data/public/search/aggs/types.ts b/src/plugins/data/public/search/aggs/types.ts index 94f61fc51eaa2..a784bfaada4c7 100644 --- a/src/plugins/data/public/search/aggs/types.ts +++ b/src/plugins/data/public/search/aggs/types.ts @@ -21,6 +21,14 @@ import { IndexPattern } from '../../index_patterns'; import { AggConfigSerialized, AggConfigs, + AggParamsRange, + AggParamsIpRange, + AggParamsDateRange, + AggParamsFilter, + AggParamsFilters, + AggParamsSignificantTerms, + AggParamsGeoTile, + AggParamsGeoHash, AggParamsTerms, AggParamsAvg, AggParamsCardinality, @@ -42,11 +50,14 @@ import { AggParamsPercentiles, AggParamsSerialDiff, AggParamsTopHit, + AggParamsHistogram, + AggParamsDateHistogram, AggTypesRegistrySetup, AggTypesRegistryStart, CreateAggConfigParams, getCalculateAutoTimeExpression, METRIC_TYPES, + BUCKET_TYPES, } from './'; export { IAggConfig, AggConfigSerialized } from './agg_config'; @@ -101,7 +112,17 @@ export type AggExpressionFunctionArgs< * @internal */ export interface AggParamsMapping { - terms: AggParamsTerms; + [BUCKET_TYPES.RANGE]: AggParamsRange; + [BUCKET_TYPES.IP_RANGE]: AggParamsIpRange; + [BUCKET_TYPES.DATE_RANGE]: AggParamsDateRange; + [BUCKET_TYPES.FILTER]: AggParamsFilter; + [BUCKET_TYPES.FILTERS]: AggParamsFilters; + [BUCKET_TYPES.SIGNIFICANT_TERMS]: AggParamsSignificantTerms; + [BUCKET_TYPES.GEOTILE_GRID]: AggParamsGeoTile; + [BUCKET_TYPES.GEOHASH_GRID]: AggParamsGeoHash; + [BUCKET_TYPES.HISTOGRAM]: AggParamsHistogram; + [BUCKET_TYPES.DATE_HISTOGRAM]: AggParamsDateHistogram; + [BUCKET_TYPES.TERMS]: AggParamsTerms; [METRIC_TYPES.AVG]: AggParamsAvg; [METRIC_TYPES.CARDINALITY]: AggParamsCardinality; [METRIC_TYPES.COUNT]: BaseAggParams; diff --git a/src/plugins/dev_tools/public/application.tsx b/src/plugins/dev_tools/public/application.tsx index 2c21b451cb9f7..5ec5b8036e4fb 100644 --- a/src/plugins/dev_tools/public/application.tsx +++ b/src/plugins/dev_tools/public/application.tsx @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import { I18nProvider } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { EuiTab, EuiTabs, EuiToolTip } from '@elastic/eui'; @@ -26,17 +25,17 @@ import ReactDOM from 'react-dom'; import { useEffect, useRef } from 'react'; import { AppMountContext, AppMountDeprecated } from 'kibana/public'; -import { DevTool } from './plugin'; +import { DevToolApp } from './dev_tool'; interface DevToolsWrapperProps { - devTools: readonly DevTool[]; - activeDevTool: DevTool; + devTools: readonly DevToolApp[]; + activeDevTool: DevToolApp; appMountContext: AppMountContext; updateRoute: (newRoute: string) => void; } interface MountedDevToolDescriptor { - devTool: DevTool; + devTool: DevToolApp; mountpoint: HTMLElement; unmountHandler: () => void; } @@ -64,10 +63,10 @@ function DevToolsWrapper({ {devTools.map(currentDevTool => ( { - if (!currentDevTool.disabled) { + if (!currentDevTool.isDisabled()) { updateRoute(`/dev_tools/${currentDevTool.id}`); } }} @@ -151,7 +150,7 @@ export function renderApp( element: HTMLElement, appMountContext: AppMountContext, basePath: string, - devTools: readonly DevTool[] + devTools: readonly DevToolApp[] ) { if (redirectOnMissingCapabilities(appMountContext)) { return () => {}; @@ -162,21 +161,24 @@ export function renderApp( - {devTools.map(devTool => ( - ( - - )} - /> - ))} + {devTools + // Only create routes for devtools that are not disabled + .filter(devTool => !devTool.isDisabled()) + .map(devTool => ( + ( + + )} + /> + ))} diff --git a/src/plugins/dev_tools/public/dev_tool.ts b/src/plugins/dev_tools/public/dev_tool.ts new file mode 100644 index 0000000000000..943cca286a722 --- /dev/null +++ b/src/plugins/dev_tools/public/dev_tool.ts @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { App } from 'kibana/public'; + +/** + * Descriptor for a dev tool. A dev tool works similar to an application + * registered in the core application service. + */ +export type CreateDevToolArgs = Omit & { + disabled?: boolean; +}; + +export class DevToolApp { + /** + * The id of the dev tools. This will become part of the URL path + * (`dev_tools/${devTool.id}`. It has to be unique among registered + * dev tools. + */ + public readonly id: string; + /** + * The human readable name of the dev tool. Should be internationalized. + * This will be used as a label in the tab above the actual tool. + */ + public readonly title: string; + public readonly mount: App['mount']; + + /** + * Flag indicating to disable the tab of this dev tool. Navigating to a + * disabled dev tool will be treated as the navigation to an unknown route + * (redirect to the console). + */ + private disabled: boolean; + + /** + * Optional tooltip content of the tab. + */ + public readonly tooltipContent?: string; + /** + * Flag indicating whether the dev tool will do routing within the `dev_tools/${devTool.id}/` + * prefix. If it is set to true, the dev tool is responsible to redirect + * the user when navigating to unknown URLs within the prefix. If set + * to false only the root URL of the dev tool will be recognized as valid. + */ + public readonly enableRouting: boolean; + /** + * Number used to order the tabs. + */ + public readonly order: number; + + constructor( + id: string, + title: string, + mount: App['mount'], + enableRouting: boolean, + order: number, + toolTipContent = '', + disabled = false + ) { + this.id = id; + this.title = title; + this.mount = mount; + this.enableRouting = enableRouting; + this.order = order; + this.tooltipContent = toolTipContent; + this.disabled = disabled; + } + + public enable() { + this.disabled = false; + } + + public disable() { + this.disabled = true; + } + + public isDisabled(): boolean { + return this.disabled; + } +} + +export const createDevToolApp = ({ + id, + title, + mount, + enableRouting, + order, + tooltipContent, + disabled, +}: CreateDevToolArgs) => + new DevToolApp(id, title, mount, enableRouting, order, tooltipContent, disabled); diff --git a/src/plugins/dev_tools/public/plugin.ts b/src/plugins/dev_tools/public/plugin.ts index df61271baf879..bedf92818315a 100644 --- a/src/plugins/dev_tools/public/plugin.ts +++ b/src/plugins/dev_tools/public/plugin.ts @@ -17,9 +17,10 @@ * under the License. */ -import { App, CoreSetup, Plugin } from 'kibana/public'; +import { CoreSetup, Plugin } from 'kibana/public'; import { sortBy } from 'lodash'; import { KibanaLegacySetup } from '../../kibana_legacy/public'; +import { CreateDevToolArgs, DevToolApp, createDevToolApp } from './dev_tool'; import './index.scss'; @@ -34,7 +35,7 @@ export interface DevToolsSetup { * to switch between the tools. * @param devTool The dev tools descriptor */ - register: (devTool: DevTool) => void; + register: (devTool: CreateDevToolArgs) => DevToolApp; } export interface DevToolsStart { @@ -46,53 +47,13 @@ export interface DevToolsStart { * becomes an implementation detail. * @deprecated */ - getSortedDevTools: () => readonly DevTool[]; -} - -/** - * Descriptor for a dev tool. A dev tool works similar to an application - * registered in the core application service. - */ -export interface DevTool { - /** - * The id of the dev tools. This will become part of the URL path - * (`dev_tools/${devTool.id}`. It has to be unique among registered - * dev tools. - */ - id: string; - /** - * The human readable name of the dev tool. Should be internationalized. - * This will be used as a label in the tab above the actual tool. - */ - title: string; - mount: App['mount']; - /** - * Flag indicating to disable the tab of this dev tool. Navigating to a - * disabled dev tool will be treated as the navigation to an unknown route - * (redirect to the console). - */ - disabled?: boolean; - /** - * Optional tooltip content of the tab. - */ - tooltipContent?: string; - /** - * Flag indicating whether the dev tool will do routing within the `dev_tools/${devTool.id}/` - * prefix. If it is set to true, the dev tool is responsible to redirect - * the user when navigating to unknown URLs within the prefix. If set - * to false only the root URL of the dev tool will be recognized as valid. - */ - enableRouting: boolean; - /** - * Number used to order the tabs. - */ - order: number; + getSortedDevTools: () => readonly DevToolApp[]; } export class DevToolsPlugin implements Plugin { - private readonly devTools = new Map(); + private readonly devTools = new Map(); - private getSortedDevTools(): readonly DevTool[] { + private getSortedDevTools(): readonly DevToolApp[] { return sortBy([...this.devTools.values()], 'order'); } @@ -115,14 +76,16 @@ export class DevToolsPlugin implements Plugin { }); return { - register: (devTool: DevTool) => { - if (this.devTools.has(devTool.id)) { + register: (devToolArgs: CreateDevToolArgs) => { + if (this.devTools.has(devToolArgs.id)) { throw new Error( - `Dev tool with id [${devTool.id}] has already been registered. Use a unique id.` + `Dev tool with id [${devToolArgs.id}] has already been registered. Use a unique id.` ); } + const devTool = createDevToolApp(devToolArgs); this.devTools.set(devTool.id, devTool); + return devTool; }, }; } diff --git a/src/plugins/discover/kibana.json b/src/plugins/discover/kibana.json index 2d41293f26369..0b3a07e98624e 100644 --- a/src/plugins/discover/kibana.json +++ b/src/plugins/discover/kibana.json @@ -2,5 +2,16 @@ "id": "discover", "version": "kibana", "server": true, - "ui": true + "ui": true, + "requiredPlugins": [ + "charts", + "data", + "embeddable", + "inspector", + "kibanaLegacy", + "navigation", + "uiActions", + "visualizations" + ], + "optionalPlugins": ["home", "share"] } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss b/src/plugins/discover/public/application/_discover.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/_discover.scss rename to src/plugins/discover/public/application/_discover.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/_hacks.scss b/src/plugins/discover/public/application/_hacks.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/_hacks.scss rename to src/plugins/discover/public/application/_hacks.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/_mixins.scss b/src/plugins/discover/public/application/_mixins.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/_mixins.scss rename to src/plugins/discover/public/application/_mixins.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/_index.scss b/src/plugins/discover/public/application/angular/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/_index.scss rename to src/plugins/discover/public/application/angular/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.html b/src/plugins/discover/public/application/angular/context.html similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.html rename to src/plugins/discover/public/application/angular/context.html diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js b/src/plugins/discover/public/application/angular/context.js similarity index 98% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js rename to src/plugins/discover/public/application/angular/context.js index 032ec7af09a30..33bbc8cb2e6cf 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context.js +++ b/src/plugins/discover/public/application/angular/context.js @@ -32,7 +32,7 @@ const k7Breadcrumbs = $route => { return [ ...getRootBreadcrumbs(), { - text: i18n.translate('kbn.context.breadcrumb', { + text: i18n.translate('discover.context.breadcrumb', { defaultMessage: 'Context of {indexPatternTitle}#{docId}', values: { indexPatternTitle: indexPattern.title, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/NOTES.md b/src/plugins/discover/public/application/angular/context/NOTES.md similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/NOTES.md rename to src/plugins/discover/public/application/angular/context/NOTES.md diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/_index.scss b/src/plugins/discover/public/application/angular/context/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/_index.scss rename to src/plugins/discover/public/application/angular/context/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/_stubs.js b/src/plugins/discover/public/application/angular/context/api/_stubs.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/_stubs.js rename to src/plugins/discover/public/application/angular/context/api/_stubs.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/anchor.js b/src/plugins/discover/public/application/angular/context/api/anchor.js similarity index 95% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/anchor.js rename to src/plugins/discover/public/application/angular/context/api/anchor.js index 4338d3e1dbdbd..4df5ba989f798 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/anchor.js +++ b/src/plugins/discover/public/application/angular/context/api/anchor.js @@ -46,7 +46,7 @@ export function fetchAnchorProvider(indexPatterns, searchSource) { if (_.get(response, ['hits', 'total'], 0) < 1) { throw new Error( - i18n.translate('kbn.context.failedToLoadAnchorDocumentErrorDescription', { + i18n.translate('discover.context.failedToLoadAnchorDocumentErrorDescription', { defaultMessage: 'Failed to load anchor document.', }) ); diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/anchor.test.js b/src/plugins/discover/public/application/angular/context/api/anchor.test.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/anchor.test.js rename to src/plugins/discover/public/application/angular/context/api/anchor.test.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.predecessors.test.js b/src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.predecessors.test.js rename to src/plugins/discover/public/application/angular/context/api/context.predecessors.test.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.successors.test.js b/src/plugins/discover/public/application/angular/context/api/context.successors.test.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.successors.test.js rename to src/plugins/discover/public/application/angular/context/api/context.successors.test.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.ts b/src/plugins/discover/public/application/angular/context/api/context.ts similarity index 97% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.ts rename to src/plugins/discover/public/application/angular/context/api/context.ts index 2760eec38755e..0bca820f9a723 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/context.ts +++ b/src/plugins/discover/public/application/angular/context/api/context.ts @@ -17,17 +17,13 @@ * under the License. */ +import { Filter, IndexPatternsContract, IndexPattern } from 'src/plugins/data/public'; import { reverseSortDir, SortDirection } from './utils/sorting'; import { extractNanos, convertIsoToMillis } from './utils/date_conversion'; import { fetchHitsInInterval } from './utils/fetch_hits_in_interval'; import { generateIntervals } from './utils/generate_intervals'; import { getEsQuerySearchAfter } from './utils/get_es_query_search_after'; import { getEsQuerySort } from './utils/get_es_query_sort'; -import { - Filter, - IndexPatternsContract, - IndexPattern, -} from '../../../../../../../../../plugins/data/public'; import { getServices } from '../../../../kibana_services'; export type SurrDocType = 'successors' | 'predecessors'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/date_conversion.test.ts b/src/plugins/discover/public/application/angular/context/api/utils/date_conversion.test.ts similarity index 96% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/date_conversion.test.ts rename to src/plugins/discover/public/application/angular/context/api/utils/date_conversion.test.ts index b9ec105cc0e7b..223b174718296 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/date_conversion.test.ts +++ b/src/plugins/discover/public/application/angular/context/api/utils/date_conversion.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { extractNanos } from '../date_conversion'; +import { extractNanos } from './date_conversion'; describe('function extractNanos', function() { test('extract nanos of 2014-01-01', function() { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/date_conversion.ts b/src/plugins/discover/public/application/angular/context/api/utils/date_conversion.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/date_conversion.ts rename to src/plugins/discover/public/application/angular/context/api/utils/date_conversion.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts b/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts similarity index 95% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts rename to src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts index 8eed5d33ab004..437898201863f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/fetch_hits_in_interval.ts +++ b/src/plugins/discover/public/application/angular/context/api/utils/fetch_hits_in_interval.ts @@ -16,11 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { - ISearchSource, - EsQuerySortValue, - SortDirection, -} from '../../../../../../../../../../plugins/data/public'; +import { ISearchSource, EsQuerySortValue, SortDirection } from '../../../../../../../data/public'; import { convertTimeValueToIso } from './date_conversion'; import { EsHitRecordList } from '../context'; import { IntervalValue } from './generate_intervals'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/generate_intervals.ts b/src/plugins/discover/public/application/angular/context/api/utils/generate_intervals.ts similarity index 95% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/generate_intervals.ts rename to src/plugins/discover/public/application/angular/context/api/utils/generate_intervals.ts index b14180d32b4f2..1497f54aa5079 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/generate_intervals.ts +++ b/src/plugins/discover/public/application/angular/context/api/utils/generate_intervals.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { SortDirection } from '../../../../../../../../../../plugins/data/public'; +import { SortDirection } from '../../../../../../../data/public'; export type IntervalValue = number | null; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/get_es_query_search_after.ts b/src/plugins/discover/public/application/angular/context/api/utils/get_es_query_search_after.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/get_es_query_search_after.ts rename to src/plugins/discover/public/application/angular/context/api/utils/get_es_query_search_after.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/get_es_query_sort.ts b/src/plugins/discover/public/application/angular/context/api/utils/get_es_query_sort.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/get_es_query_sort.ts rename to src/plugins/discover/public/application/angular/context/api/utils/get_es_query_sort.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/sorting.test.ts b/src/plugins/discover/public/application/angular/context/api/utils/sorting.test.ts similarity index 94% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/sorting.test.ts rename to src/plugins/discover/public/application/angular/context/api/utils/sorting.test.ts index eeae2aa2c5d0a..350a0a8ede8d5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/__tests__/sorting.test.ts +++ b/src/plugins/discover/public/application/angular/context/api/utils/sorting.test.ts @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { reverseSortDir, SortDirection } from '../sorting'; +import { reverseSortDir, SortDirection } from './sorting'; describe('function reverseSortDir', function() { test('reverse a given sort direction', function() { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/sorting.ts b/src/plugins/discover/public/application/angular/context/api/utils/sorting.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/api/utils/sorting.ts rename to src/plugins/discover/public/application/angular/context/api/utils/sorting.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/_action_bar.scss b/src/plugins/discover/public/application/angular/context/components/action_bar/_action_bar.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/_action_bar.scss rename to src/plugins/discover/public/application/angular/context/components/action_bar/_action_bar.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/_index.scss b/src/plugins/discover/public/application/angular/context/components/action_bar/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/_index.scss rename to src/plugins/discover/public/application/angular/context/components/action_bar/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar.test.tsx b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar.test.tsx rename to src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar.tsx b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.tsx similarity index 93% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar.tsx rename to src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.tsx index 8fcfcba08955c..97a29ab21c581 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar.tsx +++ b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar.tsx @@ -111,7 +111,7 @@ export function ActionBar({ }} flush="right" > - + @@ -119,10 +119,10 @@ export function ActionBar({ {isSuccessor ? ( ) : ( )} diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar_directive.ts b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar_directive.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar_directive.ts rename to src/plugins/discover/public/application/angular/context/components/action_bar/action_bar_directive.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar_warning.tsx b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar_warning.tsx similarity index 90% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar_warning.tsx rename to src/plugins/discover/public/application/angular/context/components/action_bar/action_bar_warning.tsx index 6b922bb05a243..db757881ad819 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/action_bar_warning.tsx +++ b/src/plugins/discover/public/application/angular/context/components/action_bar/action_bar_warning.tsx @@ -31,12 +31,12 @@ export function ActionBarWarning({ docCount, type }: { docCount: number; type: S title={ docCount === 0 ? ( ) : ( @@ -55,12 +55,12 @@ export function ActionBarWarning({ docCount, type }: { docCount: number; type: S title={ docCount === 0 ? ( ) : ( diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/index.ts b/src/plugins/discover/public/application/angular/context/components/action_bar/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/components/action_bar/index.ts rename to src/plugins/discover/public/application/angular/context/components/action_bar/index.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/helpers/call_after_bindings_workaround.js b/src/plugins/discover/public/application/angular/context/helpers/call_after_bindings_workaround.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/helpers/call_after_bindings_workaround.js rename to src/plugins/discover/public/application/angular/context/helpers/call_after_bindings_workaround.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/actions.js b/src/plugins/discover/public/application/angular/context/query/actions.js similarity index 95% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/actions.js rename to src/plugins/discover/public/application/angular/context/query/actions.js index efc230d2cd4ae..1b1fa7138bfda 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/actions.js +++ b/src/plugins/discover/public/application/angular/context/query/actions.js @@ -26,7 +26,7 @@ import { fetchAnchorProvider } from '../api/anchor'; import { fetchContextProvider } from '../api/context'; import { getQueryParameterActions } from '../query_parameters'; import { FAILURE_REASONS, LOADING_STATUS } from './constants'; -import { MarkdownSimple } from '../../../../../../../../../plugins/kibana_react/public'; +import { MarkdownSimple } from '../../../../../../kibana_react/public'; export function QueryActionsProvider(Promise) { const { filterManager, indexPatterns, data } = getServices(); @@ -80,7 +80,7 @@ export function QueryActionsProvider(Promise) { error => { setFailedStatus(state)('anchor', { error }); getServices().toastNotifications.addDanger({ - title: i18n.translate('kbn.context.unableToLoadAnchorDocumentDescription', { + title: i18n.translate('discover.context.unableToLoadAnchorDocumentDescription', { defaultMessage: 'Unable to load the anchor document', }), text: {error.message}, @@ -133,7 +133,7 @@ export function QueryActionsProvider(Promise) { error => { setFailedStatus(state)(type, { error }); getServices().toastNotifications.addDanger({ - title: i18n.translate('kbn.context.unableToLoadDocumentDescription', { + title: i18n.translate('discover.context.unableToLoadDocumentDescription', { defaultMessage: 'Unable to load documents', }), text: {error.message}, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/constants.js b/src/plugins/discover/public/application/angular/context/query/constants.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/constants.js rename to src/plugins/discover/public/application/angular/context/query/constants.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/index.js b/src/plugins/discover/public/application/angular/context/query/index.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/index.js rename to src/plugins/discover/public/application/angular/context/query/index.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/state.js b/src/plugins/discover/public/application/angular/context/query/state.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query/state.js rename to src/plugins/discover/public/application/angular/context/query/state.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.js b/src/plugins/discover/public/application/angular/context/query_parameters/actions.js similarity index 96% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.js rename to src/plugins/discover/public/application/angular/context/query_parameters/actions.js index 5c1700e776361..4f86dea08fe84 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.js +++ b/src/plugins/discover/public/application/angular/context/query_parameters/actions.js @@ -18,7 +18,7 @@ */ import _ from 'lodash'; -import { esFilters } from '../../../../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../data/public'; import { MAX_CONTEXT_SIZE, MIN_CONTEXT_SIZE, QUERY_PARAMETER_KEYS } from './constants'; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.test.ts b/src/plugins/discover/public/application/angular/context/query_parameters/actions.test.ts similarity index 97% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.test.ts rename to src/plugins/discover/public/application/angular/context/query_parameters/actions.test.ts index 35fbd33fb4bc9..00747fcc81227 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/actions.test.ts +++ b/src/plugins/discover/public/application/angular/context/query_parameters/actions.test.ts @@ -19,8 +19,8 @@ // @ts-ignore import { getQueryParameterActions } from './actions'; -import { FilterManager } from '../../../../../../../../../plugins/data/public'; -import { coreMock } from '../../../../../../../../../core/public/mocks'; +import { FilterManager } from '../../../../../../data/public'; +import { coreMock } from '../../../../../../../core/public/mocks'; const setupMock = coreMock.createSetup(); let state: { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/constants.ts b/src/plugins/discover/public/application/angular/context/query_parameters/constants.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/constants.ts rename to src/plugins/discover/public/application/angular/context/query_parameters/constants.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/index.js b/src/plugins/discover/public/application/angular/context/query_parameters/index.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/index.js rename to src/plugins/discover/public/application/angular/context/query_parameters/index.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/state.ts b/src/plugins/discover/public/application/angular/context/query_parameters/state.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context/query_parameters/state.ts rename to src/plugins/discover/public/application/angular/context/query_parameters/state.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html b/src/plugins/discover/public/application/angular/context_app.html similarity index 78% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html rename to src/plugins/discover/public/application/angular/context_app.html index 8bbb746fa45f8..1f2d6a073150b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.html +++ b/src/plugins/discover/public/application/angular/context_app.html @@ -21,7 +21,7 @@
@@ -30,7 +30,7 @@
@@ -92,7 +92,7 @@ >
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js b/src/plugins/discover/public/application/angular/context_app.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_app.js rename to src/plugins/discover/public/application/angular/context_app.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.test.ts b/src/plugins/discover/public/application/angular/context_state.test.ts similarity index 97% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.test.ts rename to src/plugins/discover/public/application/angular/context_state.test.ts index 1fa71ed11643a..83bf1b1d7e3d5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.test.ts +++ b/src/plugins/discover/public/application/angular/context_state.test.ts @@ -19,8 +19,8 @@ import { getState } from './context_state'; import { createBrowserHistory, History } from 'history'; -import { FilterManager, Filter } from '../../../../../../../plugins/data/public'; -import { coreMock } from '../../../../../../../core/public/mocks'; +import { FilterManager, Filter } from '../../../../data/public'; +import { coreMock } from '../../../../../core/public/mocks'; const setupMock = coreMock.createSetup(); describe('Test Discover Context State', () => { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts b/src/plugins/discover/public/application/angular/context_state.ts similarity index 98% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts rename to src/plugins/discover/public/application/angular/context_state.ts index b46995d44d826..7a92a6ace125b 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/context_state.ts +++ b/src/plugins/discover/public/application/angular/context_state.ts @@ -23,8 +23,8 @@ import { createKbnUrlStateStorage, syncStates, BaseStateContainer, -} from '../../../../../../../plugins/kibana_utils/public'; -import { esFilters, FilterManager, Filter, Query } from '../../../../../../../plugins/data/public'; +} from '../../../../kibana_utils/public'; +import { esFilters, FilterManager, Filter, Query } from '../../../../data/public'; export interface AppState { /** diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap b/src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/__snapshots__/no_results.test.js.snap rename to src/plugins/discover/public/application/angular/directives/__snapshots__/no_results.test.js.snap diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_histogram.scss b/src/plugins/discover/public/application/angular/directives/_histogram.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_histogram.scss rename to src/plugins/discover/public/application/angular/directives/_histogram.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_index.scss b/src/plugins/discover/public/application/angular/directives/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_index.scss rename to src/plugins/discover/public/application/angular/directives/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_no_results.scss b/src/plugins/discover/public/application/angular/directives/_no_results.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/_no_results.scss rename to src/plugins/discover/public/application/angular/directives/_no_results.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_collapsible_sidebar.scss b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_collapsible_sidebar.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_collapsible_sidebar.scss rename to src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_collapsible_sidebar.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_depth.scss b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_depth.scss rename to src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_depth.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_index.scss b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/_index.scss rename to src/plugins/discover/public/application/angular/directives/collapsible_sidebar/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/collapsible_sidebar.ts b/src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/collapsible_sidebar/collapsible_sidebar.ts rename to src/plugins/discover/public/application/angular/directives/collapsible_sidebar/collapsible_sidebar.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/debounce.js b/src/plugins/discover/public/application/angular/directives/debounce/debounce.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/debounce.js rename to src/plugins/discover/public/application/angular/directives/debounce/debounce.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/__tests__/debounce.js b/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts similarity index 73% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/__tests__/debounce.js rename to src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts index 43fa5ffbf299a..bc08d8566d48a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/__tests__/debounce.js +++ b/src/plugins/discover/public/application/angular/directives/debounce/debounce.test.ts @@ -17,42 +17,56 @@ * under the License. */ -import sinon from 'sinon'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import { DebounceProvider } from '../index'; -import { pluginInstance } from 'plugins/kibana/discover/legacy'; - -let debounce; -let debounceFromProvider; -let $timeout; - -function init() { - pluginInstance.initializeServices(); - pluginInstance.initializeInnerAngular(); - ngMock.module('app/discover'); - - ngMock.inject(function($injector, _$timeout_, Private) { - $timeout = _$timeout_; - - debounce = $injector.get('debounce'); - debounceFromProvider = Private(DebounceProvider); - }); -} +import sinon, { SinonSpy } from 'sinon'; +import angular, { auto, ITimeoutService } from 'angular'; +import 'angular-mocks'; +import 'angular-sanitize'; +import 'angular-route'; + +// @ts-ignore +import { DebounceProvider } from './index'; +import { coreMock } from '../../../../../../../core/public/mocks'; +import { initializeInnerAngularModule } from '../../../../get_inner_angular'; +import { navigationPluginMock } from '../../../../../../navigation/public/mocks'; +import { dataPluginMock } from '../../../../../../data/public/mocks'; +import { initAngularBootstrap } from '../../../../../../kibana_legacy/public'; describe('debounce service', function() { - let spy; - beforeEach(function() { + let debounce: (fn: () => void, timeout: number, options?: any) => any; + let debounceFromProvider: (fn: () => void, timeout: number, options?: any) => any; + let $timeout: ITimeoutService; + let spy: SinonSpy; + + beforeEach(() => { spy = sinon.spy(); - init(); + + initAngularBootstrap(); + + initializeInnerAngularModule( + 'app/discover', + coreMock.createStart(), + navigationPluginMock.createStartContract(), + dataPluginMock.createStartContract() + ); + + angular.mock.module('app/discover'); + + angular.mock.inject( + ($injector: auto.IInjectorService, _$timeout_: ITimeoutService, Private: any) => { + $timeout = _$timeout_; + + debounce = $injector.get('debounce'); + debounceFromProvider = Private(DebounceProvider); + } + ); }); it('should have a cancel method', function() { const bouncer = debounce(() => {}, 100); const bouncerFromProvider = debounceFromProvider(() => {}, 100); - expect(bouncer).to.have.property('cancel'); - expect(bouncerFromProvider).to.have.property('cancel'); + expect(bouncer).toHaveProperty('cancel'); + expect(bouncerFromProvider).toHaveProperty('cancel'); }); describe('delayed execution', function() { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/index.js b/src/plugins/discover/public/application/angular/directives/debounce/index.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/debounce/index.js rename to src/plugins/discover/public/application/angular/directives/debounce/index.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/fixed_scroll.js b/src/plugins/discover/public/application/angular/directives/fixed_scroll.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/fixed_scroll.js rename to src/plugins/discover/public/application/angular/directives/fixed_scroll.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx b/src/plugins/discover/public/application/angular/directives/histogram.tsx similarity index 97% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx rename to src/plugins/discover/public/application/angular/directives/histogram.tsx index 8c55622e4c604..d856be58958f1 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/histogram.tsx +++ b/src/plugins/discover/public/application/angular/directives/histogram.tsx @@ -39,6 +39,7 @@ import { TooltipType, ElementClickListener, XYChartElementEvent, + BrushEndListener, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; @@ -143,13 +144,12 @@ export class DiscoverHistogram extends Component { - const range = { - from: min, - to: max, - }; - - this.props.timefilterUpdateHandler(range); + public onBrushEnd: BrushEndListener = ({ x }) => { + if (!x) { + return; + } + const [from, to] = x; + this.props.timefilterUpdateHandler({ from, to }); }; public onElementClick = (xInterval: number): ElementClickListener => ([elementData]) => { @@ -175,7 +175,7 @@ export class DiscoverHistogram extends Component

@@ -114,14 +114,14 @@ export class DiscoverNoResults extends Component {

@@ -155,7 +155,7 @@ export class DiscoverNoResults extends Component { @@ -168,7 +168,7 @@ export class DiscoverNoResults extends Component { @@ -181,7 +181,7 @@ export class DiscoverNoResults extends Component { @@ -194,7 +194,7 @@ export class DiscoverNoResults extends Component { @@ -210,14 +210,14 @@ export class DiscoverNoResults extends Component {

@@ -256,7 +256,7 @@ export class DiscoverNoResults extends Component { } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js b/src/plugins/discover/public/application/angular/directives/no_results.test.js similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/no_results.test.js rename to src/plugins/discover/public/application/angular/directives/no_results.test.js diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/render_complete.ts b/src/plugins/discover/public/application/angular/directives/render_complete.ts similarity index 92% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/render_complete.ts rename to src/plugins/discover/public/application/angular/directives/render_complete.ts index 7757deb806a18..635cf68f12fcb 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/render_complete.ts +++ b/src/plugins/discover/public/application/angular/directives/render_complete.ts @@ -17,7 +17,7 @@ * under the License. */ import { IScope } from 'angular'; -import { RenderCompleteHelper } from '../../../../../../../../plugins/kibana_utils/public'; +import { RenderCompleteHelper } from '../../../../../kibana_utils/public'; export function createRenderCompleteDirective() { return { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/uninitialized.tsx b/src/plugins/discover/public/application/angular/directives/uninitialized.tsx similarity index 92% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/uninitialized.tsx rename to src/plugins/discover/public/application/angular/directives/uninitialized.tsx index b308607bbfbb0..d04aea0933115 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/directives/uninitialized.tsx +++ b/src/plugins/discover/public/application/angular/directives/uninitialized.tsx @@ -37,7 +37,7 @@ export const DiscoverUninitialized = ({ onRefresh }: Props) => { title={

@@ -45,7 +45,7 @@ export const DiscoverUninitialized = ({ onRefresh }: Props) => { body={

@@ -53,7 +53,7 @@ export const DiscoverUninitialized = ({ onRefresh }: Props) => { actions={ diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html b/src/plugins/discover/public/application/angular/discover.html similarity index 89% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html rename to src/plugins/discover/public/application/angular/discover.html index 1221b01657e45..b4db89b9275b4 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.html +++ b/src/plugins/discover/public/application/angular/discover.html @@ -61,7 +61,7 @@

{{screenTitle}}

@@ -83,7 +83,7 @@

{{screenTitle}}

@@ -93,7 +93,7 @@

{{screenTitle}}

{{(hits || 0) | number:0}} @@ -104,12 +104,12 @@

{{screenTitle}}

id="reload_saved_search" ng-click="resetQuery()" > - {{::'kbn.discover.reloadSavedSearchButton' | i18n: {defaultMessage: 'Reset search'} }} + {{::'discover.reloadSavedSearchButton' | i18n: {defaultMessage: 'Reset search'} }}
@@ -117,7 +117,7 @@

{{screenTitle}}

@@ -141,7 +141,7 @@

{{screenTitle}}

> {{screenTitle}} >

{{screenTitle}} class="dscTable__footer" > {{screenTitle}}
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/plugins/discover/public/application/angular/discover.js similarity index 93% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js rename to src/plugins/discover/public/application/angular/discover.js index c1de704d1c00a..2afd0322f8701 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/plugins/discover/public/application/angular/discover.js @@ -26,11 +26,8 @@ import dateMath from '@elastic/datemath'; import { i18n } from '@kbn/i18n'; import { getState, splitState } from './discover_state'; -import { RequestAdapter } from '../../../../../../../plugins/inspector/public'; -import { - SavedObjectSaveModal, - showSaveModal, -} from '../../../../../../../plugins/saved_objects/public'; +import { RequestAdapter } from '../../../../inspector/public'; +import { SavedObjectSaveModal, showSaveModal } from '../../../../saved_objects/public'; import { getSortArray, getSortForSearchSource } from './doc_table'; import * as columnActions from './doc_table/actions/columns'; @@ -75,9 +72,9 @@ import { syncQueryStateWithUrl, getDefaultQuery, search, -} from '../../../../../../../plugins/data/public'; +} from '../../../../data/public'; import { getIndexPatternId } from '../helpers/get_index_pattern_id'; -import { addFatalError } from '../../../../../../../plugins/kibana_legacy/public'; +import { addFatalError } from '../../../../kibana_legacy/public'; const fetchStatuses = { UNINITIALIZED: 'uninitialized', @@ -99,10 +96,10 @@ app.config($routeProvider => { } return { - text: i18n.translate('kbn.discover.badge.readOnly.text', { + text: i18n.translate('discover.badge.readOnly.text', { defaultMessage: 'Read only', }), - tooltip: i18n.translate('kbn.discover.badge.readOnly.tooltip', { + tooltip: i18n.translate('discover.badge.readOnly.tooltip', { defaultMessage: 'Unable to save searches', }), iconType: 'glasses', @@ -333,10 +330,10 @@ function discoverController( const getTopNavLinks = () => { const newSearch = { id: 'new', - label: i18n.translate('kbn.discover.localMenu.localMenu.newSearchTitle', { + label: i18n.translate('discover.localMenu.localMenu.newSearchTitle', { defaultMessage: 'New', }), - description: i18n.translate('kbn.discover.localMenu.newSearchDescription', { + description: i18n.translate('discover.localMenu.newSearchDescription', { defaultMessage: 'New Search', }), run: function() { @@ -349,10 +346,10 @@ function discoverController( const saveSearch = { id: 'save', - label: i18n.translate('kbn.discover.localMenu.saveTitle', { + label: i18n.translate('discover.localMenu.saveTitle', { defaultMessage: 'Save', }), - description: i18n.translate('kbn.discover.localMenu.saveSearchDescription', { + description: i18n.translate('discover.localMenu.saveSearchDescription', { defaultMessage: 'Save Search', }), testId: 'discoverSaveButton', @@ -389,7 +386,7 @@ function discoverController( title={savedSearch.title} showCopyOnSave={!!savedSearch.id} objectType="search" - description={i18n.translate('kbn.discover.localMenu.saveSaveSearchDescription', { + description={i18n.translate('discover.localMenu.saveSaveSearchDescription', { defaultMessage: 'Save your Discover search so you can use it in visualizations and dashboards', })} @@ -402,10 +399,10 @@ function discoverController( const openSearch = { id: 'open', - label: i18n.translate('kbn.discover.localMenu.openTitle', { + label: i18n.translate('discover.localMenu.openTitle', { defaultMessage: 'Open', }), - description: i18n.translate('kbn.discover.localMenu.openSavedSearchDescription', { + description: i18n.translate('discover.localMenu.openSavedSearchDescription', { defaultMessage: 'Open Saved Search', }), testId: 'discoverOpenButton', @@ -419,10 +416,10 @@ function discoverController( const shareSearch = { id: 'share', - label: i18n.translate('kbn.discover.localMenu.shareTitle', { + label: i18n.translate('discover.localMenu.shareTitle', { defaultMessage: 'Share', }), - description: i18n.translate('kbn.discover.localMenu.shareSearchDescription', { + description: i18n.translate('discover.localMenu.shareSearchDescription', { defaultMessage: 'Share Search', }), testId: 'shareTopNavButton', @@ -446,10 +443,10 @@ function discoverController( const inspectSearch = { id: 'inspect', - label: i18n.translate('kbn.discover.localMenu.inspectTitle', { + label: i18n.translate('discover.localMenu.inspectTitle', { defaultMessage: 'Inspect', }), - description: i18n.translate('kbn.discover.localMenu.openInspectorForSearchDescription', { + description: i18n.translate('discover.localMenu.openInspectorForSearchDescription', { defaultMessage: 'Open Inspector for search', }), testId: 'openInspectorButton', @@ -492,7 +489,7 @@ function discoverController( const pageTitleSuffix = savedSearch.id && savedSearch.title ? `: ${savedSearch.title}` : ''; chrome.docTitle.change(`Discover${pageTitleSuffix}`); - const discoverBreadcrumbsTitle = i18n.translate('kbn.discover.discoverBreadcrumbTitle', { + const discoverBreadcrumbsTitle = i18n.translate('discover.discoverBreadcrumbTitle', { defaultMessage: 'Discover', }); @@ -606,16 +603,16 @@ function discoverController( $scope.state.sort = getSortArray($scope.state.sort, $scope.indexPattern); $scope.getBucketIntervalToolTipText = () => { - return i18n.translate('kbn.discover.bucketIntervalTooltip', { + return i18n.translate('discover.bucketIntervalTooltip', { defaultMessage: 'This interval creates {bucketsDescription} to show in the selected time range, so it has been scaled to {bucketIntervalDescription}', values: { bucketsDescription: $scope.bucketInterval.scale > 1 - ? i18n.translate('kbn.discover.bucketIntervalTooltip.tooLargeBucketsText', { + ? i18n.translate('discover.bucketIntervalTooltip.tooLargeBucketsText', { defaultMessage: 'buckets that are too large', }) - : i18n.translate('kbn.discover.bucketIntervalTooltip.tooManyBucketsText', { + : i18n.translate('discover.bucketIntervalTooltip.tooManyBucketsText', { defaultMessage: 'too many buckets', }), bucketIntervalDescription: $scope.bucketInterval.description, @@ -748,7 +745,7 @@ function discoverController( $scope.$evalAsync(() => { if (id) { toastNotifications.addSuccess({ - title: i18n.translate('kbn.discover.notifications.savedSearchTitle', { + title: i18n.translate('discover.notifications.savedSearchTitle', { defaultMessage: `Search '{savedSearchTitle}' was saved`, values: { savedSearchTitle: savedSearch.title, @@ -769,7 +766,7 @@ function discoverController( return { id }; } catch (saveError) { toastNotifications.addDanger({ - title: i18n.translate('kbn.discover.notifications.notSavedSearchTitle', { + title: i18n.translate('discover.notifications.notSavedSearchTitle', { defaultMessage: `Search '{savedSearchTitle}' was not saved.`, values: { savedSearchTitle: savedSearch.title, @@ -812,7 +809,7 @@ function discoverController( $scope.fetchError = fetchError; } else { toastNotifications.addError(error, { - title: i18n.translate('kbn.discover.errorLoadingData', { + title: i18n.translate('discover.errorLoadingData', { defaultMessage: 'Error loading data', }), toastMessage: error.shortMessage || error.body?.message, @@ -903,10 +900,10 @@ function discoverController( function logInspectorRequest() { inspectorAdapters.requests.reset(); - const title = i18n.translate('kbn.discover.inspectorRequestDataTitle', { + const title = i18n.translate('discover.inspectorRequestDataTitle', { defaultMessage: 'data', }); - const description = i18n.translate('kbn.discover.inspectorRequestDescription', { + const description = i18n.translate('discover.inspectorRequestDescription', { defaultMessage: 'This request queries Elasticsearch to fetch the data for the search.', }); inspectorRequest = inspectorAdapters.requests.start(title, { description }); @@ -1049,7 +1046,7 @@ function discoverController( } function getIndexPatternWarning(index) { - return i18n.translate('kbn.discover.valueIsNotConfiguredIndexPatternIDWarningTitle', { + return i18n.translate('discover.valueIsNotConfiguredIndexPatternIDWarningTitle', { defaultMessage: '{stateVal} is not a configured index pattern ID', values: { stateVal: `"${index}"`, @@ -1076,7 +1073,7 @@ function discoverController( if (ownIndexPattern) { toastNotifications.addWarning({ title: warningTitle, - text: i18n.translate('kbn.discover.showingSavedIndexPatternWarningDescription', { + text: i18n.translate('discover.showingSavedIndexPatternWarningDescription', { defaultMessage: 'Showing the saved index pattern: "{ownIndexPatternTitle}" ({ownIndexPatternId})', values: { @@ -1090,7 +1087,7 @@ function discoverController( toastNotifications.addWarning({ title: warningTitle, - text: i18n.translate('kbn.discover.showingDefaultIndexPatternWarningDescription', { + text: i18n.translate('discover.showingDefaultIndexPatternWarningDescription', { defaultMessage: 'Showing the default index pattern: "{loadedIndexPatternTitle}" ({loadedIndexPatternId})', values: { diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts b/src/plugins/discover/public/application/angular/discover_state.test.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.test.ts rename to src/plugins/discover/public/application/angular/discover_state.test.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts b/src/plugins/discover/public/application/angular/discover_state.ts similarity index 96% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts rename to src/plugins/discover/public/application/angular/discover_state.ts index 2a036f0ac60ad..46500d9fdf85e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover_state.ts +++ b/src/plugins/discover/public/application/angular/discover_state.ts @@ -24,9 +24,9 @@ import { syncState, ReduxLikeStateContainer, IKbnUrlStateStorage, -} from '../../../../../../../plugins/kibana_utils/public'; -import { esFilters, Filter, Query } from '../../../../../../../plugins/data/public'; -import { migrateLegacyQuery } from '../../../../../../../plugins/kibana_legacy/public'; +} from '../../../../kibana_utils/public'; +import { esFilters, Filter, Query } from '../../../../data/public'; +import { migrateLegacyQuery } from '../../../../kibana_legacy/public'; export interface AppState { /** diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc.html b/src/plugins/discover/public/application/angular/doc.html similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc.html rename to src/plugins/discover/public/application/angular/doc.html diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc.ts b/src/plugins/discover/public/application/angular/doc.ts similarity index 91% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc.ts rename to src/plugins/discover/public/application/angular/doc.ts index 092e3c79b1007..2d0d45e5003fb 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc.ts +++ b/src/plugins/discover/public/application/angular/doc.ts @@ -49,7 +49,9 @@ app.config(($routeProvider: any) => { }) // the new route, es 7 deprecated types, es 8 removed them .when('/discover/doc/:indexPattern/:index', { - controller: ($scope: LazyScope, $route: any, es: any) => { + // have to be written as function expression, because it's not compiled in dev mode + // eslint-disable-next-line object-shorthand + controller: function($scope: LazyScope, $route: any, es: any) { timefilter.disableAutoRefreshSelector(); timefilter.disableTimeRangeSelector(); $scope.esClient = es; diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/_doc_table.scss b/src/plugins/discover/public/application/angular/doc_table/_doc_table.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/_doc_table.scss rename to src/plugins/discover/public/application/angular/doc_table/_doc_table.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/_index.scss b/src/plugins/discover/public/application/angular/doc_table/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/_index.scss rename to src/plugins/discover/public/application/angular/doc_table/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts b/src/plugins/discover/public/application/angular/doc_table/actions/columns.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/actions/columns.ts rename to src/plugins/discover/public/application/angular/doc_table/actions/columns.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/_index.scss b/src/plugins/discover/public/application/angular/doc_table/components/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/_index.scss rename to src/plugins/discover/public/application/angular/doc_table/components/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/_table_header.scss b/src/plugins/discover/public/application/angular/doc_table/components/_table_header.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/_table_header.scss rename to src/plugins/discover/public/application/angular/doc_table/components/_table_header.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_buttons.test.tsx.snap b/src/plugins/discover/public/application/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_buttons.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_buttons.test.tsx.snap rename to src/plugins/discover/public/application/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_buttons.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_text.test.tsx.snap b/src/plugins/discover/public/application/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_text.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_text.test.tsx.snap rename to src/plugins/discover/public/application/angular/doc_table/components/pager/__snapshots__/tool_bar_pager_text.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/index.ts b/src/plugins/discover/public/application/angular/doc_table/components/pager/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/index.ts rename to src/plugins/discover/public/application/angular/doc_table/components/pager/index.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx similarity index 92% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx index 6f1cf81e2c541..e95153d85b064 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_buttons.tsx @@ -35,7 +35,7 @@ export function ToolBarPagerButtons(props: Props) { disabled={!props.hasPreviousPage} data-test-subj="btnPrevPage" aria-label={i18n.translate( - 'kbn.discover.docTable.pager.toolbarPagerButtons.previousButtonAriaLabel', + 'discover.docTable.pager.toolbarPagerButtons.previousButtonAriaLabel', { defaultMessage: 'Previous page in table', } @@ -49,7 +49,7 @@ export function ToolBarPagerButtons(props: Props) { disabled={!props.hasNextPage} data-test-subj="btnNextPage" aria-label={i18n.translate( - 'kbn.discover.docTable.pager.toolbarPagerButtons.nextButtonAriaLabel', + 'discover.docTable.pager.toolbarPagerButtons.nextButtonAriaLabel', { defaultMessage: 'Next page in table', } diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_text.test.tsx b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_text.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_text.test.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_text.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_text.tsx b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_text.tsx similarity index 95% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_text.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_text.tsx index 84338d817c86b..46e3cd9511eb5 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/pager/tool_bar_pager_text.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/pager/tool_bar_pager_text.tsx @@ -30,7 +30,7 @@ export function ToolBarPagerText({ startItem, endItem, totalItems }: Props) {
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header.ts b/src/plugins/discover/public/application/angular/doc_table/components/table_header.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header.ts rename to src/plugins/discover/public/application/angular/doc_table/components/table_header.ts diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap b/src/plugins/discover/public/application/angular/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap rename to src/plugins/discover/public/application/angular/doc_table/components/table_header/__snapshots__/table_header.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx b/src/plugins/discover/public/application/angular/doc_table/components/table_header/helpers.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/helpers.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/table_header/helpers.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx similarity index 99% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx index 89f73022627c5..b201bea26503e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.test.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.test.tsx @@ -25,8 +25,6 @@ import { findTestSubject } from '@elastic/eui/lib/test'; import { SortOrder } from './helpers'; import { IndexPattern, IFieldType } from '../../../../../kibana_services'; -jest.mock('ui/new_platform'); - function getMockIndexPattern() { return ({ id: 'test', diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header_column.tsx b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header_column.tsx similarity index 88% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header_column.tsx rename to src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header_column.tsx index d1a9a5146fb8a..4c09ff8701f30 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_header/table_header_column.tsx +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_header/table_header_column.tsx @@ -80,21 +80,21 @@ export function TableHeaderColumn({ const getSortButtonAriaLabel = () => { const sortAscendingMessage = i18n.translate( - 'kbn.docTable.tableHeader.sortByColumnAscendingAriaLabel', + 'discover.docTable.tableHeader.sortByColumnAscendingAriaLabel', { defaultMessage: 'Sort {columnName} ascending', values: { columnName: name }, } ); const sortDescendingMessage = i18n.translate( - 'kbn.docTable.tableHeader.sortByColumnDescendingAriaLabel', + 'discover.docTable.tableHeader.sortByColumnDescendingAriaLabel', { defaultMessage: 'Sort {columnName} descending', values: { columnName: name }, } ); const stopSortingMessage = i18n.translate( - 'kbn.docTable.tableHeader.sortByColumnUnsortedAriaLabel', + 'discover.docTable.tableHeader.sortByColumnUnsortedAriaLabel', { defaultMessage: 'Stop sorting on {columnName}', values: { columnName: name }, @@ -126,42 +126,42 @@ export function TableHeaderColumn({ // Remove Button { active: isRemoveable && typeof onRemoveColumn === 'function', - ariaLabel: i18n.translate('kbn.docTable.tableHeader.removeColumnButtonAriaLabel', { + ariaLabel: i18n.translate('discover.docTable.tableHeader.removeColumnButtonAriaLabel', { defaultMessage: 'Remove {columnName} column', values: { columnName: name }, }), className: 'fa fa-remove kbnDocTableHeader__move', onClick: () => onRemoveColumn && onRemoveColumn(name), testSubject: `docTableRemoveHeader-${name}`, - tooltip: i18n.translate('kbn.docTable.tableHeader.removeColumnButtonTooltip', { + tooltip: i18n.translate('discover.docTable.tableHeader.removeColumnButtonTooltip', { defaultMessage: 'Remove Column', }), }, // Move Left Button { active: colLeftIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('kbn.docTable.tableHeader.moveColumnLeftButtonAriaLabel', { + ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonAriaLabel', { defaultMessage: 'Move {columnName} column to the left', values: { columnName: name }, }), className: 'fa fa-angle-double-left kbnDocTableHeader__move', onClick: () => onMoveColumn && onMoveColumn(name, colLeftIdx), testSubject: `docTableMoveLeftHeader-${name}`, - tooltip: i18n.translate('kbn.docTable.tableHeader.moveColumnLeftButtonTooltip', { + tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonTooltip', { defaultMessage: 'Move column to the left', }), }, // Move Right Button { active: colRightIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('kbn.docTable.tableHeader.moveColumnRightButtonAriaLabel', { + ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonAriaLabel', { defaultMessage: 'Move {columnName} column to the right', values: { columnName: name }, }), className: 'fa fa-angle-double-right kbnDocTableHeader__move', onClick: () => onMoveColumn && onMoveColumn(name, colRightIdx), testSubject: `docTableMoveRightHeader-${name}`, - tooltip: i18n.translate('kbn.docTable.tableHeader.moveColumnRightButtonTooltip', { + tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonTooltip', { defaultMessage: 'Move column to the right', }), }, diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts b/src/plugins/discover/public/application/angular/doc_table/components/table_row.ts similarity index 96% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts rename to src/plugins/discover/public/application/angular/doc_table/components/table_row.ts index 698bfe7416d42..3b48c4c79365e 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row.ts +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_row.ts @@ -23,15 +23,15 @@ import $ from 'jquery'; import rison from 'rison-node'; import '../../doc_viewer'; // @ts-ignore -import { noWhiteSpace } from '../../../../../../common/utils/no_white_space'; +import { noWhiteSpace } from '../../../../../../../legacy/core_plugins/kibana/common/utils/no_white_space'; import openRowHtml from './table_row/open.html'; import detailsHtml from './table_row/details.html'; -import { dispatchRenderComplete } from '../../../../../../../../../plugins/kibana_utils/public'; +import { dispatchRenderComplete } from '../../../../../../kibana_utils/public'; import cellTemplateHtml from '../components/table_row/cell.html'; import truncateByHeightTemplateHtml from '../components/table_row/truncate_by_height.html'; -import { esFilters } from '../../../../../../../../../plugins/data/public'; +import { esFilters } from '../../../../../../data/public'; import { getServices } from '../../../../kibana_services'; // guesstimate at the minimum number of chars wide cells in the table should be diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_cell.scss b/src/plugins/discover/public/application/angular/doc_table/components/table_row/_cell.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_cell.scss rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/_cell.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_details.scss b/src/plugins/discover/public/application/angular/doc_table/components/table_row/_details.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_details.scss rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/_details.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_index.scss b/src/plugins/discover/public/application/angular/doc_table/components/table_row/_index.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_index.scss rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/_index.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_open.scss b/src/plugins/discover/public/application/angular/doc_table/components/table_row/_open.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/_open.scss rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/_open.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/cell.html b/src/plugins/discover/public/application/angular/doc_table/components/table_row/cell.html similarity index 66% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/cell.html rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/cell.html index 0704016a52bbd..e8c4fceeca7ff 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/cell.html +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_row/cell.html @@ -18,17 +18,17 @@ data-column="<%- column %>" tooltip-append-to-body="1" data-test-subj="docTableCellFilter" - tooltip="{{ ::'kbn.docTable.tableRow.filterForValueButtonTooltip' | i18n: {defaultMessage: 'Filter for value'} }}" + tooltip="{{ ::'discover.docTable.tableRow.filterForValueButtonTooltip' | i18n: {defaultMessage: 'Filter for value'} }}" tooltip-placement="bottom" - aria-label="{{ ::'kbn.docTable.tableRow.filterForValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter for value'} }}" + aria-label="{{ ::'discover.docTable.tableRow.filterForValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter for value'} }}" > diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/details.html b/src/plugins/discover/public/application/angular/doc_table/components/table_row/details.html similarity index 89% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/details.html rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/details.html index d149a9023816a..37ae08246d1d3 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/details.html +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_row/details.html @@ -8,7 +8,7 @@

@@ -22,7 +22,7 @@ data-test-subj="docTableRowAction" ng-href="{{ getContextAppHref() }}" ng-if="indexPattern.isTimeBased()" - i18n-id="kbn.docTable.tableRow.viewSurroundingDocumentsLinkText" + i18n-id="discover.docTable.tableRow.viewSurroundingDocumentsLinkText" i18n-default-message="View surrounding documents" >
@@ -31,7 +31,7 @@ class="euiLink" data-test-subj="docTableRowAction" ng-href="#/discover/doc/{{indexPattern.id}}/{{row._index}}?id={{uriEncodedId}}" - i18n-id="kbn.docTable.tableRow.viewSingleDocumentLinkText" + i18n-id="discover.docTable.tableRow.viewSingleDocumentLinkText" i18n-default-message="View single document" >
diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/open.html b/src/plugins/discover/public/application/angular/doc_table/components/table_row/open.html similarity index 72% rename from src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/open.html rename to src/plugins/discover/public/application/angular/doc_table/components/table_row/open.html index d6c4b858d2b47..6a14b6fc70348 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/doc_table/components/table_row/open.html +++ b/src/plugins/discover/public/application/angular/doc_table/components/table_row/open.html @@ -2,7 +2,7 @@