diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f27885c1e32c3..d14556ea1dabf 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -348,6 +348,7 @@
# Security Solution sub teams
/x-pack/plugins/case @elastic/security-threat-hunting
+/x-pack/plugins/timelines @elastic/security-threat-hunting
/x-pack/test/case_api_integration @elastic/security-threat-hunting
/x-pack/plugins/lists @elastic/security-detections-response
diff --git a/docs/api/actions-and-connectors/legacy/create.asciidoc b/docs/api/actions-and-connectors/legacy/create.asciidoc
index af4feddcb80fb..0361c4222986b 100644
--- a/docs/api/actions-and-connectors/legacy/create.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/create.asciidoc
@@ -4,7 +4,7 @@
Legacy Create connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Creates a connector.
diff --git a/docs/api/actions-and-connectors/legacy/delete.asciidoc b/docs/api/actions-and-connectors/legacy/delete.asciidoc
index 170fceba2d157..9ec2c0d392a96 100644
--- a/docs/api/actions-and-connectors/legacy/delete.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/delete.asciidoc
@@ -4,7 +4,7 @@
Legacy Delete connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Deletes a connector by ID.
diff --git a/docs/api/actions-and-connectors/legacy/execute.asciidoc b/docs/api/actions-and-connectors/legacy/execute.asciidoc
index 200844ab72f17..f01aa1585b192 100644
--- a/docs/api/actions-and-connectors/legacy/execute.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/execute.asciidoc
@@ -4,7 +4,7 @@
Legacy Execute connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Executes a connector by ID.
diff --git a/docs/api/actions-and-connectors/legacy/get.asciidoc b/docs/api/actions-and-connectors/legacy/get.asciidoc
index 1b138fb7032e0..6413fce558f5b 100644
--- a/docs/api/actions-and-connectors/legacy/get.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/get.asciidoc
@@ -4,7 +4,7 @@
Legacy Get connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieves a connector by ID.
diff --git a/docs/api/actions-and-connectors/legacy/get_all.asciidoc b/docs/api/actions-and-connectors/legacy/get_all.asciidoc
index ba235955c005e..191eccb6f8d39 100644
--- a/docs/api/actions-and-connectors/legacy/get_all.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/get_all.asciidoc
@@ -4,7 +4,7 @@
Legacy Get all connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieves all connectors.
diff --git a/docs/api/actions-and-connectors/legacy/list.asciidoc b/docs/api/actions-and-connectors/legacy/list.asciidoc
index 8acfd5415af57..d78838dcbe974 100644
--- a/docs/api/actions-and-connectors/legacy/list.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/list.asciidoc
@@ -4,7 +4,7 @@
Legacy List all connector types
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieves a list of all connector types.
diff --git a/docs/api/actions-and-connectors/legacy/update.asciidoc b/docs/api/actions-and-connectors/legacy/update.asciidoc
index 517daf9a40dca..6a33e765cf063 100644
--- a/docs/api/actions-and-connectors/legacy/update.asciidoc
+++ b/docs/api/actions-and-connectors/legacy/update.asciidoc
@@ -4,7 +4,7 @@
Legacy Update connector
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Updates the attributes for an existing connector.
diff --git a/docs/api/alerting/legacy/create.asciidoc b/docs/api/alerting/legacy/create.asciidoc
index 5c594d64a3f45..8363569541356 100644
--- a/docs/api/alerting/legacy/create.asciidoc
+++ b/docs/api/alerting/legacy/create.asciidoc
@@ -4,7 +4,7 @@
Legacy create alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Create {kib} alerts.
diff --git a/docs/api/alerting/legacy/delete.asciidoc b/docs/api/alerting/legacy/delete.asciidoc
index 68851973cab5b..2af420f2bc34e 100644
--- a/docs/api/alerting/legacy/delete.asciidoc
+++ b/docs/api/alerting/legacy/delete.asciidoc
@@ -4,7 +4,7 @@
Legacy delete alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Permanently remove an alert.
diff --git a/docs/api/alerting/legacy/disable.asciidoc b/docs/api/alerting/legacy/disable.asciidoc
index 56e06371570c2..1a9b928bfba78 100644
--- a/docs/api/alerting/legacy/disable.asciidoc
+++ b/docs/api/alerting/legacy/disable.asciidoc
@@ -4,7 +4,7 @@
Legacy disable alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Disable an alert.
diff --git a/docs/api/alerting/legacy/enable.asciidoc b/docs/api/alerting/legacy/enable.asciidoc
index 913d96a84352b..da4b466d6fda4 100644
--- a/docs/api/alerting/legacy/enable.asciidoc
+++ b/docs/api/alerting/legacy/enable.asciidoc
@@ -4,7 +4,7 @@
Legacy enable alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Enable an alert.
diff --git a/docs/api/alerting/legacy/find.asciidoc b/docs/api/alerting/legacy/find.asciidoc
index 94d9bc425bd21..7c493e9c8eb5b 100644
--- a/docs/api/alerting/legacy/find.asciidoc
+++ b/docs/api/alerting/legacy/find.asciidoc
@@ -4,7 +4,7 @@
Legacy find alerts
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieve a paginated set of alerts based on condition.
diff --git a/docs/api/alerting/legacy/get.asciidoc b/docs/api/alerting/legacy/get.asciidoc
index f1014d18e8774..ee0f52f51005a 100644
--- a/docs/api/alerting/legacy/get.asciidoc
+++ b/docs/api/alerting/legacy/get.asciidoc
@@ -4,7 +4,7 @@
Legacy get alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieve an alert by ID.
diff --git a/docs/api/alerting/legacy/health.asciidoc b/docs/api/alerting/legacy/health.asciidoc
index b25307fb5efd1..68f04cc715bd7 100644
--- a/docs/api/alerting/legacy/health.asciidoc
+++ b/docs/api/alerting/legacy/health.asciidoc
@@ -4,7 +4,7 @@
Legacy get Alerting framework health
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieve the health status of the Alerting framework.
diff --git a/docs/api/alerting/legacy/list.asciidoc b/docs/api/alerting/legacy/list.asciidoc
index e9ef3bbc27cd9..be37be36cd0e8 100644
--- a/docs/api/alerting/legacy/list.asciidoc
+++ b/docs/api/alerting/legacy/list.asciidoc
@@ -4,7 +4,7 @@
Legacy list all alert types
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Retrieve a list of all alert types.
diff --git a/docs/api/alerting/legacy/mute.asciidoc b/docs/api/alerting/legacy/mute.asciidoc
index dff42f5911e53..cf7adc446a2fd 100644
--- a/docs/api/alerting/legacy/mute.asciidoc
+++ b/docs/api/alerting/legacy/mute.asciidoc
@@ -4,7 +4,7 @@
Legacy mute alert instance
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Mute an alert instance.
diff --git a/docs/api/alerting/legacy/mute_all.asciidoc b/docs/api/alerting/legacy/mute_all.asciidoc
index df89fa15d1590..bc865480340e2 100644
--- a/docs/api/alerting/legacy/mute_all.asciidoc
+++ b/docs/api/alerting/legacy/mute_all.asciidoc
@@ -4,7 +4,7 @@
Legacy mute all alert instances
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Mute all alert instances.
diff --git a/docs/api/alerting/legacy/unmute.asciidoc b/docs/api/alerting/legacy/unmute.asciidoc
index 0be7e40dc1a19..300cf71b57a01 100644
--- a/docs/api/alerting/legacy/unmute.asciidoc
+++ b/docs/api/alerting/legacy/unmute.asciidoc
@@ -4,7 +4,7 @@
Legacy unmute alert instance
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Unmute an alert instance.
diff --git a/docs/api/alerting/legacy/unmute_all.asciidoc b/docs/api/alerting/legacy/unmute_all.asciidoc
index 8687c2d2fe8bb..3b0a7afe5f44d 100644
--- a/docs/api/alerting/legacy/unmute_all.asciidoc
+++ b/docs/api/alerting/legacy/unmute_all.asciidoc
@@ -4,7 +4,7 @@
Legacy unmute all alert instances
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Unmute all alert instances.
diff --git a/docs/api/alerting/legacy/update.asciidoc b/docs/api/alerting/legacy/update.asciidoc
index bffdf26c31400..b9cce995660e6 100644
--- a/docs/api/alerting/legacy/update.asciidoc
+++ b/docs/api/alerting/legacy/update.asciidoc
@@ -4,7 +4,7 @@
Legacy update alert
++++
-WARNING: Deprecated in 7.13.0. Use <> instead.
+deprecated::[7.13.0,Use <> instead.]
Update the attributes for an existing alert.
diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc
index e1c2c40a31384..bcf74936077ec 100644
--- a/docs/developer/plugin-list.asciidoc
+++ b/docs/developer/plugin-list.asciidoc
@@ -537,6 +537,10 @@ Documentation: https://www.elastic.co/guide/en/kibana/master/task-manager-produc
|Gathers all usage collection, retrieving them from both: OSS and X-Pack plugins.
+|{kib-repo}blob/{branch}/x-pack/plugins/timelines/README.md[timelines]
+|Timelines is a plugin that provides a grid component with accompanying server side apis to help users identify events of interest and perform root cause analysis within Kibana.
+
+
|{kib-repo}blob/{branch}/x-pack/plugins/transform/readme.md[transform]
|This plugin provides access to the transforms features provided by Elastic.
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.md
index d408f00e33c9e..b5c7d8931ad4b 100644
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.md
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.md
@@ -14,6 +14,6 @@ export declare class IndexPatternsServiceProvider implements PluginSignature:
```typescript
-setup(core: CoreSetup, { expressions }: IndexPatternsServiceSetupDeps): void;
+setup(core: CoreSetup, { expressions, usageCollection }: IndexPatternsServiceSetupDeps): void;
```
## Parameters
| Parameter | Type | Description |
| --- | --- | --- |
-| core | CoreSetup<DataPluginStartDependencies, DataPluginStart>
| |
-| { expressions } | IndexPatternsServiceSetupDeps
| |
+| core | CoreSetup<IndexPatternsServiceStartDeps, DataPluginStart>
| |
+| { expressions, usageCollection } | IndexPatternsServiceSetupDeps
| |
Returns:
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.start.md
index 98f9310c6d98c..88079bb2fa3cb 100644
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.start.md
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.indexpatternsserviceprovider.start.md
@@ -8,7 +8,7 @@
```typescript
start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps): {
- indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract, elasticsearchClient: ElasticsearchClient) => Promise;
+ indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: ElasticsearchClient) => Promise;
};
```
@@ -22,6 +22,6 @@ start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps):
Returns:
`{
- indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract, elasticsearchClient: ElasticsearchClient) => Promise;
+ indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: ElasticsearchClient) => Promise;
}`
diff --git a/docs/management/managing-fields.asciidoc b/docs/management/managing-fields.asciidoc
index 5cd5c1ffd6248..505f6853c7906 100644
--- a/docs/management/managing-fields.asciidoc
+++ b/docs/management/managing-fields.asciidoc
@@ -78,6 +78,7 @@ include::field-formatters/color-formatter.asciidoc[]
[[scripted-fields]]
=== Scripted fields
+deprecated::[7.13,Use {ref}/runtime.html[runtime fields] instead of scripted fields. Runtime fields support Painless scripts and provide greater flexibility.]
Scripted fields compute data on the fly from the data in your {es} indices. The data is shown on
the Discover tab as part of the document data, and you can use scripted fields in your visualizations. You query scripted fields with the <>, and can filter them using the filter bar. The scripted field values are computed at query time, so they aren't indexed and cannot be searched using the {kib} default
@@ -87,7 +88,7 @@ WARNING: Computing data on the fly with scripted fields can be very resource int
{kib} performance. Keep in mind that there's no built-in validation of a scripted field. If your scripts are
buggy, you'll get exceptions whenever you try to view the dynamically generated data.
-When you define a scripted field in {kib}, you have a choice of the {ref}/modules-scripting-expression.html[Lucene expressions] or the
+When you define a scripted field in {kib}, you have a choice of the {ref}/modules-scripting-expression.html[Lucene expressions] or the
{ref}/modules-scripting-painless.html[Painless] scripting language.
You can reference any single value numeric field in your expressions, for example:
diff --git a/docs/migration/migrate_8_0.asciidoc b/docs/migration/migrate_8_0.asciidoc
index f5ebac1ebf02e..acb343191609d 100644
--- a/docs/migration/migrate_8_0.asciidoc
+++ b/docs/migration/migrate_8_0.asciidoc
@@ -320,6 +320,15 @@ All supported operating systems support using systemd service files. Any system
*Impact:*
Any installations using `.deb` or `.rpm` packages using SysV will need to migrate to systemd.
+[float]
+=== TLS v1.0 and v1.1 are disabled by default
+
+*Details:*
+Support can be re-enabled by setting `--tls-min-1.0` in the `node.options` config file that can be found inside `kibana/config` folder or any other configured with the environment variable `KBN_PATH_CONF` (for example in Debian based system would be `/etc/kibana`).
+
+*Impact:*
+Browser and proxy clients communicating over TLS v1.0 and v1.1.
+
[float]
=== Platform removed from root folder name for `.tar.gz` and `.zip` archives
diff --git a/docs/settings/reporting-settings.asciidoc b/docs/settings/reporting-settings.asciidoc
index cef5a953fded4..9bb11f3f99a15 100644
--- a/docs/settings/reporting-settings.asciidoc
+++ b/docs/settings/reporting-settings.asciidoc
@@ -260,19 +260,21 @@ For information about {kib} memory limits, see <> setting. Defaults to `.reporting`.
-
| `xpack.reporting.capture.networkPolicy`
| Capturing a screenshot from a {kib} page involves sending out requests for all the linked web assets. For example, a Markdown
visualization can show an image from a remote server. You can configure what type of requests to allow or filter by setting a
<> for Reporting.
+| `xpack.reporting.index`
+ | deprecated:[7.11.0,This setting will be removed in 8.0.] Multitenancy by
+ changing `kibana.index` will not be supported starting in 8.0. See
+ https://ela.st/kbn-remove-legacy-multitenancy[8.0 Breaking Changes] for more
+ details. 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 <>
+ setting. Defaults to `.reporting`.
+
| `xpack.reporting.roles.allow`
| Specifies the roles in addition to superusers that can use reporting.
Defaults to `[ "reporting_user" ]`. +
diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc
index e5cbc2c7ea6db..73b268e1e48b3 100644
--- a/docs/setup/settings.asciidoc
+++ b/docs/setup/settings.asciidoc
@@ -25,12 +25,14 @@ which may cause a delay before pages start being served.
Set to `false` to disable Console. *Default: `true`*
| `cpu.cgroup.path.override:`
- | *deprecated* This setting has been renamed to <>
-and the old name will no longer be supported as of 8.0.
+ | deprecated:[7.10.0,"This setting will no longer be supported as of 8.0."]
+ This setting has been renamed to
+ <>.
| `cpuacct.cgroup.path.override:`
- | *deprecated* This setting has been renamed to <>
-and the old name will no longer be supported as of 8.0.
+ | deprecated:[7.10.0,"This setting will no longer be supported as of 8.0."]
+ This setting has been renamed to
+ <>.
| `csp.rules:`
| A https://w3c.github.io/webappsec-csp/[content-security-policy] template
@@ -64,10 +66,12 @@ To enable SSL/TLS for outbound connections to {es}, use the `https` protocol
in this setting.
| `elasticsearch.logQueries:`
- | *deprecated* This setting is no longer used and will get removed in Kibana 8.0. Instead, configure the `elasticsearch.query` logger.
-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`*
+ | deprecated:[7.12.0,"This setting is no longer used and will be removed in Kibana 8.0."]
+ Instead, configure the `elasticsearch.query` logger.
+ +
+ 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`*
The following example shows a valid `elasticsearch.query` logger configuration:
|===
@@ -240,18 +244,22 @@ on the {kib} index at startup. {kib} users still need to authenticate with
| Enables use of interpreter in Visualize. *Default: `true`*
| `kibana.defaultAppId:`
- | *deprecated* This setting is deprecated and will get removed in Kibana 8.0.
-Please use the `defaultRoute` advanced setting instead.
-The default application to load. *Default: `"home"`*
+ | deprecated:[7.9.0,This setting will be removed in Kibana 8.0.]
+ Instead, use the <>.
+ +
+ The default application to load. *Default: `"home"`*
|[[kibana-index]] `kibana.index:`
- | *deprecated* This setting is deprecated and will be removed in 8.0. Multitenancy by changing
-`kibana.index` will not be supported starting in 8.0. See https://ela.st/kbn-remove-legacy-multitenancy[8.0 Breaking Changes]
-for more details. {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"`*
+ | deprecated:[7.11.0,This setting will be removed in 8.0.] Multitenancy by
+ changing `kibana.index` will not be supported starting in 8.0. See
+ https://ela.st/kbn-remove-legacy-multitenancy[8.0 Breaking Changes] for more
+ details.
+ +
+ {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:` {ess-icon}
| Time in milliseconds to wait for autocomplete suggestions from {es}.
diff --git a/docs/user/dashboard/timelion.asciidoc b/docs/user/dashboard/timelion.asciidoc
index 676c46368a6ee..80ce77f30c75e 100644
--- a/docs/user/dashboard/timelion.asciidoc
+++ b/docs/user/dashboard/timelion.asciidoc
@@ -4,17 +4,7 @@
Instead of using a visual editor to create charts, you define a graph by chaining functions together, using the *Timelion*-specific syntax.
The syntax enables some features that classical point series charts don't offer, such as pulling data from different indices or data sources into one graph.
-[NOTE]
-====
-Timelion app deprecation
-
-*Timelion* is still supported, the *Timelion app* is deprecated in 7.0, replaced by
-dashboard features. In 8.0 and later, the *Timelion app* is removed from {kib}.
-To prepare for the removal of *Timelion app*, you must migrate *Timelion app* worksheets to a dashboard.
-
-For information on how to migrate *Timelion app* worksheets, refer to the
-link:https://www.elastic.co/guide/en/kibana/7.10/release-notes-7.10.0.html#deprecation-v7.10.0[7.10.0 Release Notes].
-====
+deprecated::[7.0.0,"*Timelion* is still supported. The *Timelion app* is deprecated in 7.0, replaced by dashboard features. In 8.0 and later, the *Timelion app* is removed from {kib}. To prepare for the removal of *Timelion app*, you must migrate *Timelion app* worksheets to a dashboard. For information on how to migrate *Timelion app* worksheets, refer to the link:https://www.elastic.co/guide/en/kibana/7.10/release-notes-7.10.0.html#deprecation-v7.10.0[7.10.0 Release Notes]."]
[float]
==== Timelion expressions
diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml
index f93849e011d41..3c9fd4f59a406 100644
--- a/packages/kbn-optimizer/limits.yml
+++ b/packages/kbn-optimizer/limits.yml
@@ -9,7 +9,7 @@ pageLoadAssetSize:
charts: 195358
cloud: 21076
console: 46091
- core: 692106
+ core: 397521
crossClusterReplication: 65408
dashboard: 374194
dashboardEnhanced: 65646
@@ -24,13 +24,13 @@ pageLoadAssetSize:
enterpriseSearch: 35741
esUiShared: 326654
expressions: 224136
- features: 31211
- globalSearch: 43548
- globalSearchBar: 62888
+ features: 21723
+ globalSearch: 29696
+ globalSearchBar: 50403
globalSearchProviders: 25554
graph: 31504
grokdebugger: 26779
- home: 41661
+ home: 30182
indexLifecycleManagement: 107090
indexManagement: 140608
indexPatternManagement: 28222
@@ -45,11 +45,11 @@ pageLoadAssetSize:
kibanaUtils: 198829
lens: 96624
licenseManagement: 41817
- licensing: 39008
+ licensing: 29004
lists: 202261
logstash: 53548
management: 46112
- maps: 183610
+ maps: 80000
mapsLegacy: 87859
mapsLegacyLicensing: 20214
ml: 82187
@@ -73,8 +73,8 @@ pageLoadAssetSize:
share: 99061
snapshotRestore: 79032
spaces: 387915
- telemetry: 91832
- telemetryManagementSection: 52443
+ telemetry: 51957
+ telemetryManagementSection: 38586
tileMap: 65337
timelion: 29920
transform: 41007
@@ -108,3 +108,4 @@ pageLoadAssetSize:
fileUpload: 25664
banners: 17946
mapsEms: 26072
+ timelines: 28613
diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts
index 6e3106dbc2af7..d5b9996dfb2cd 100644
--- a/packages/kbn-optimizer/src/cli.ts
+++ b/packages/kbn-optimizer/src/cli.ts
@@ -6,8 +6,6 @@
* Side Public License, v 1.
*/
-import 'source-map-support/register';
-
import Path from 'path';
import { REPO_ROOT } from '@kbn/utils';
diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json
index 0fa79fff6e0d9..050aadd402d8a 100644
--- a/packages/kbn-pm/package.json
+++ b/packages/kbn-pm/package.json
@@ -9,7 +9,7 @@
},
"scripts": {
"build": "../../node_modules/.bin/webpack",
- "kbn:watch": "../../node_modules/.bin/webpack --watch --progress",
+ "kbn:watch": "../../node_modules/.bin/webpack --watch",
"prettier": "../../node_modules/.bin/prettier --write './src/**/*.ts'"
},
"devDependencies": {
diff --git a/packages/kbn-ui-shared-deps/entry.js b/packages/kbn-ui-shared-deps/entry.js
index ede617908fd3d..f14c793d22a09 100644
--- a/packages/kbn-ui-shared-deps/entry.js
+++ b/packages/kbn-ui-shared-deps/entry.js
@@ -47,3 +47,5 @@ export const LodashFp = require('lodash/fp');
// runtime deps which don't need to be copied across all bundles
export const TsLib = require('tslib');
export const KbnAnalytics = require('@kbn/analytics');
+export const KbnStd = require('@kbn/std');
+export const SaferLodashSet = require('@elastic/safer-lodash-set');
diff --git a/packages/kbn-ui-shared-deps/index.js b/packages/kbn-ui-shared-deps/index.js
index d1217dd8db0d4..0542bc89ff9e4 100644
--- a/packages/kbn-ui-shared-deps/index.js
+++ b/packages/kbn-ui-shared-deps/index.js
@@ -58,5 +58,7 @@ exports.externals = {
*/
tslib: '__kbnSharedDeps__.TsLib',
'@kbn/analytics': '__kbnSharedDeps__.KbnAnalytics',
+ '@kbn/std': '__kbnSharedDeps__.KbnStd',
+ '@elastic/safer-lodash-set': '__kbnSharedDeps__.SaferLodashSet',
};
exports.publicPathLoader = require.resolve('./public_path_loader');
diff --git a/packages/kbn-ui-shared-deps/webpack.config.js b/packages/kbn-ui-shared-deps/webpack.config.js
index 135884fbf13e7..76e6843bea2f8 100644
--- a/packages/kbn-ui-shared-deps/webpack.config.js
+++ b/packages/kbn-ui-shared-deps/webpack.config.js
@@ -177,22 +177,22 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({
compiler.hooks.emit.tap('MetricsPlugin', (compilation) => {
const metrics = [
{
- group: '@kbn/ui-shared-deps asset size',
- id: 'kbn-ui-shared-deps.js',
+ group: 'page load bundle size',
+ id: 'kbnUiSharedDeps-js',
value: compilation.assets['kbn-ui-shared-deps.js'].size(),
},
{
- group: '@kbn/ui-shared-deps asset size',
- id: 'kbn-ui-shared-deps.@elastic.js',
- value: compilation.assets['kbn-ui-shared-deps.@elastic.js'].size(),
- },
- {
- group: '@kbn/ui-shared-deps asset size',
- id: 'css',
+ group: 'page load bundle size',
+ id: 'kbnUiSharedDeps-css',
value:
compilation.assets['kbn-ui-shared-deps.css'].size() +
compilation.assets['kbn-ui-shared-deps.v7.light.css'].size(),
},
+ {
+ group: 'page load bundle size',
+ id: 'kbnUiSharedDeps-elastic',
+ value: compilation.assets['kbn-ui-shared-deps.@elastic.js'].size(),
+ },
];
compilation.emitAsset(
diff --git a/scripts/build_kibana_platform_plugins.js b/scripts/build_kibana_platform_plugins.js
index fa630e0bb1808..9038d08364400 100644
--- a/scripts/build_kibana_platform_plugins.js
+++ b/scripts/build_kibana_platform_plugins.js
@@ -7,6 +7,7 @@
*/
require('../src/setup_node_env/ensure_node_preserve_symlinks');
+require('source-map-support/register');
require('@kbn/optimizer').runKbnOptimizerCli({
defaultLimitsPath: require.resolve('../packages/kbn-optimizer/limits.yml'),
});
diff --git a/src/dev/build/tasks/bin/scripts/kibana b/src/dev/build/tasks/bin/scripts/kibana
index 3c12c8bbf58d0..a4fc5385500b5 100755
--- a/src/dev/build/tasks/bin/scripts/kibana
+++ b/src/dev/build/tasks/bin/scripts/kibana
@@ -26,4 +26,4 @@ if [ -f "${CONFIG_DIR}/node.options" ]; then
KBN_NODE_OPTS="$(grep -v ^# < ${CONFIG_DIR}/node.options | xargs)"
fi
-NODE_OPTIONS="--no-warnings --max-http-header-size=65536 --tls-min-v1.0 $KBN_NODE_OPTS $NODE_OPTIONS" NODE_ENV=production exec "${NODE}" "${DIR}/src/cli/dist" ${@}
+NODE_OPTIONS="--no-warnings --max-http-header-size=65536 $KBN_NODE_OPTS $NODE_OPTIONS" NODE_ENV=production exec "${NODE}" "${DIR}/src/cli/dist" ${@}
diff --git a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx
index 07c38fd406eea..1156bf8c6e0d1 100644
--- a/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx
+++ b/src/plugins/dashboard/public/application/actions/add_to_library_action.test.tsx
@@ -41,8 +41,15 @@ const start = doStart();
let container: DashboardContainer;
let embeddable: ContactCardEmbeddable & ReferenceOrValueEmbeddable;
let coreStart: CoreStart;
+let capabilities: CoreStart['application']['capabilities'];
+
beforeEach(async () => {
coreStart = coreMock.createStart();
+ capabilities = {
+ ...coreStart.application.capabilities,
+ visualize: { save: true },
+ maps: { save: true },
+ };
const containerOptions = {
ExitFullScreenButton: () => null,
@@ -83,7 +90,10 @@ beforeEach(async () => {
});
test('Add to library is incompatible with Error Embeddables', async () => {
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
const errorEmbeddable = new ErrorEmbeddable(
'Wow what an awful error',
{ id: ' 404' },
@@ -92,20 +102,37 @@ test('Add to library is incompatible with Error Embeddables', async () => {
expect(await action.isCompatible({ embeddable: errorEmbeddable })).toBe(false);
});
+test('Add to library is incompatible on visualize embeddable without visualize save permissions', async () => {
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities: { ...capabilities, visualize: { save: false } },
+ });
+ expect(await action.isCompatible({ embeddable })).toBe(false);
+});
+
test('Add to library is compatible when embeddable on dashboard has value type input', async () => {
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
embeddable.updateInput(await embeddable.getInputAsValueType());
expect(await action.isCompatible({ embeddable })).toBe(true);
});
test('Add to library is not compatible when embeddable input is by reference', async () => {
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
embeddable.updateInput(await embeddable.getInputAsRefType());
expect(await action.isCompatible({ embeddable })).toBe(false);
});
test('Add to library is not compatible when view mode is set to view', async () => {
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
embeddable.updateInput(await embeddable.getInputAsRefType());
embeddable.updateInput({ viewMode: ViewMode.VIEW });
expect(await action.isCompatible({ embeddable })).toBe(false);
@@ -126,7 +153,10 @@ test('Add to library is not compatible when embeddable is not in a dashboard con
mockedByReferenceInput: { savedObjectId: 'test', id: orphanContactCard.id },
mockedByValueInput: { firstName: 'Kibanana', id: orphanContactCard.id },
});
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
expect(await action.isCompatible({ embeddable: orphanContactCard })).toBe(false);
});
@@ -135,7 +165,10 @@ test('Add to library replaces embeddableId and retains panel count', async () =>
const originalPanelCount = Object.keys(dashboard.getInput().panels).length;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
await action.execute({ embeddable });
expect(Object.keys(container.getInput().panels).length).toEqual(originalPanelCount);
@@ -161,7 +194,10 @@ test('Add to library returns reference type input', async () => {
});
const dashboard = embeddable.getRoot() as IContainer;
const originalPanelKeySet = new Set(Object.keys(dashboard.getInput().panels));
- const action = new AddToLibraryAction({ toasts: coreStart.notifications.toasts });
+ const action = new AddToLibraryAction({
+ toasts: coreStart.notifications.toasts,
+ capabilities,
+ });
await action.execute({ embeddable });
const newPanelId = Object.keys(container.getInput().panels).find(
(key) => !originalPanelKeySet.has(key)
diff --git a/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx b/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx
index ef730e16bc5cf..fa102a9415b3f 100644
--- a/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx
+++ b/src/plugins/dashboard/public/application/actions/add_to_library_action.tsx
@@ -18,7 +18,7 @@ import {
isReferenceOrValueEmbeddable,
isErrorEmbeddable,
} from '../../services/embeddable';
-import { NotificationsStart } from '../../services/core';
+import { ApplicationStart, NotificationsStart } from '../../services/core';
import { dashboardAddToLibraryAction } from '../../dashboard_strings';
import { DashboardPanelState, DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '..';
@@ -33,7 +33,12 @@ export class AddToLibraryAction implements Action {
public readonly id = ACTION_ADD_TO_LIBRARY;
public order = 15;
- constructor(private deps: { toasts: NotificationsStart['toasts'] }) {}
+ constructor(
+ private deps: {
+ toasts: NotificationsStart['toasts'];
+ capabilities: ApplicationStart['capabilities'];
+ }
+ ) {}
public getDisplayName({ embeddable }: AddToLibraryActionContext) {
if (!embeddable.getRoot() || !embeddable.getRoot().isContainer) {
@@ -50,8 +55,15 @@ export class AddToLibraryAction implements Action {
}
public async isCompatible({ embeddable }: AddToLibraryActionContext) {
+ // TODO: Fix this, potentially by adding a 'canSave' function to embeddable interface
+ const canSave =
+ embeddable.type === 'map'
+ ? this.deps.capabilities.maps?.save
+ : this.deps.capabilities.visualize.save;
+
return Boolean(
- !isErrorEmbeddable(embeddable) &&
+ canSave &&
+ !isErrorEmbeddable(embeddable) &&
embeddable.getInput()?.viewMode !== ViewMode.VIEW &&
embeddable.getRoot() &&
embeddable.getRoot().isContainer &&
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 c82f17f2b29c4..829344504b16b 100644
--- a/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx
+++ b/src/plugins/dashboard/public/application/actions/clone_panel_action.tsx
@@ -61,7 +61,8 @@ export class ClonePanelAction implements Action {
embeddable.getInput()?.viewMode !== ViewMode.VIEW &&
embeddable.getRoot() &&
embeddable.getRoot().isContainer &&
- embeddable.getRoot().type === DASHBOARD_CONTAINER_TYPE
+ embeddable.getRoot().type === DASHBOARD_CONTAINER_TYPE &&
+ embeddable.getOutput().editable
);
}
diff --git a/src/plugins/dashboard/public/plugin.tsx b/src/plugins/dashboard/public/plugin.tsx
index ae2d2b5f237c9..5bf730996ab4f 100644
--- a/src/plugins/dashboard/public/plugin.tsx
+++ b/src/plugins/dashboard/public/plugin.tsx
@@ -342,7 +342,7 @@ export class DashboardPlugin
}
public start(core: CoreStart, plugins: DashboardStartDependencies): DashboardStart {
- const { notifications, overlays } = core;
+ const { notifications, overlays, application } = core;
const { uiActions, data, share, presentationUtil, embeddable } = plugins;
const SavedObjectFinder = getSavedObjectFinder(core.savedObjects, core.uiSettings);
@@ -370,7 +370,10 @@ export class DashboardPlugin
}
if (this.dashboardFeatureFlagConfig?.allowByValueEmbeddables) {
- const addToLibraryAction = new AddToLibraryAction({ toasts: notifications.toasts });
+ const addToLibraryAction = new AddToLibraryAction({
+ toasts: notifications.toasts,
+ capabilities: application.capabilities,
+ });
uiActions.registerAction(addToLibraryAction);
uiActions.attachAction(CONTEXT_MENU_TRIGGER, addToLibraryAction.id);
@@ -386,8 +389,8 @@ export class DashboardPlugin
overlays,
embeddable.getStateTransfer(),
{
- canCreateNew: Boolean(core.application.capabilities.dashboard.createNew),
- canEditExisting: !Boolean(core.application.capabilities.dashboard.hideWriteControls),
+ canCreateNew: Boolean(application.capabilities.dashboard.createNew),
+ canEditExisting: !Boolean(application.capabilities.dashboard.hideWriteControls),
},
presentationUtil.ContextProvider
);
diff --git a/src/plugins/dashboard/public/services/core.ts b/src/plugins/dashboard/public/services/core.ts
index 7c19b2d75a967..75461729841e9 100644
--- a/src/plugins/dashboard/public/services/core.ts
+++ b/src/plugins/dashboard/public/services/core.ts
@@ -12,4 +12,5 @@ export {
PluginInitializerContext,
ScopedHistory,
NotificationsStart,
+ ApplicationStart,
} from '../../../../core/public';
diff --git a/src/plugins/data/server/index_patterns/index_patterns_service.ts b/src/plugins/data/server/index_patterns/index_patterns_service.ts
index 5d703021b94da..c4cc2073ef78f 100644
--- a/src/plugins/data/server/index_patterns/index_patterns_service.ts
+++ b/src/plugins/data/server/index_patterns/index_patterns_service.ts
@@ -13,9 +13,11 @@ import {
Logger,
SavedObjectsClientContract,
ElasticsearchClient,
+ UiSettingsServiceStart,
} from 'kibana/server';
import { ExpressionsServerSetup } from 'src/plugins/expressions/server';
-import { DataPluginStartDependencies, DataPluginStart } from '../plugin';
+import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
+import { DataPluginStart } from '../plugin';
import { registerRoutes } from './routes';
import { indexPatternSavedObjectType } from '../saved_objects';
import { capabilitiesProvider } from './capabilities_provider';
@@ -25,6 +27,7 @@ import { getIndexPatternLoad } from './expressions';
import { UiSettingsServerToCommon } from './ui_settings_wrapper';
import { IndexPatternsApiServer } from './index_patterns_api_client';
import { SavedObjectsClientServerToCommon } from './saved_objects_client_wrapper';
+import { registerIndexPatternsUsageCollector } from './register_index_pattern_usage_collection';
export interface IndexPatternsServiceStart {
indexPatternsServiceFactory: (
@@ -35,6 +38,8 @@ export interface IndexPatternsServiceStart {
export interface IndexPatternsServiceSetupDeps {
expressions: ExpressionsServerSetup;
+ logger: Logger;
+ usageCollection?: UsageCollectionSetup;
}
export interface IndexPatternsServiceStartDeps {
@@ -42,10 +47,39 @@ export interface IndexPatternsServiceStartDeps {
logger: Logger;
}
+export const indexPatternsServiceFactory = ({
+ logger,
+ uiSettings,
+ fieldFormats,
+}: {
+ logger: Logger;
+ uiSettings: UiSettingsServiceStart;
+ fieldFormats: FieldFormatsStart;
+}) => async (
+ savedObjectsClient: SavedObjectsClientContract,
+ elasticsearchClient: ElasticsearchClient
+) => {
+ const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
+ const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient);
+
+ return new IndexPatternsCommonService({
+ uiSettings: new UiSettingsServerToCommon(uiSettingsClient),
+ savedObjectsClient: new SavedObjectsClientServerToCommon(savedObjectsClient),
+ apiClient: new IndexPatternsApiServer(elasticsearchClient),
+ fieldFormats: formats,
+ onError: (error) => {
+ logger.error(error);
+ },
+ onNotification: ({ title, text }) => {
+ logger.warn(`${title} : ${text}`);
+ },
+ });
+};
+
export class IndexPatternsServiceProvider implements Plugin {
public setup(
- core: CoreSetup,
- { expressions }: IndexPatternsServiceSetupDeps
+ core: CoreSetup,
+ { expressions, usageCollection }: IndexPatternsServiceSetupDeps
) {
core.savedObjects.registerType(indexPatternSavedObjectType);
core.capabilities.registerProvider(capabilitiesProvider);
@@ -53,32 +87,18 @@ export class IndexPatternsServiceProvider implements Plugin {
- const uiSettingsClient = uiSettings.asScopedToClient(savedObjectsClient);
- const formats = await fieldFormats.fieldFormatServiceFactory(uiSettingsClient);
-
- return new IndexPatternsCommonService({
- uiSettings: new UiSettingsServerToCommon(uiSettingsClient),
- savedObjectsClient: new SavedObjectsClientServerToCommon(savedObjectsClient),
- apiClient: new IndexPatternsApiServer(elasticsearchClient),
- fieldFormats: formats,
- onError: (error) => {
- logger.error(error);
- },
- onNotification: ({ title, text }) => {
- logger.warn(`${title} : ${text}`);
- },
- });
- },
+ indexPatternsServiceFactory: indexPatternsServiceFactory({
+ logger,
+ uiSettings,
+ fieldFormats,
+ }),
};
}
}
diff --git a/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.test.ts b/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.test.ts
new file mode 100644
index 0000000000000..c43431e10731a
--- /dev/null
+++ b/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.test.ts
@@ -0,0 +1,140 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import {
+ minMaxAvgLoC,
+ updateMin,
+ updateMax,
+ getIndexPatternTelemetry,
+} from './register_index_pattern_usage_collection';
+import { IndexPatternsCommonService } from '..';
+
+const scriptA = 'emit(0);';
+const scriptB = 'emit(1);\nemit(2);';
+const scriptC = 'emit(3);\nemit(4)\nemit(5)';
+
+const scriptedFieldA = { script: scriptA };
+const scriptedFieldB = { script: scriptB };
+const scriptedFieldC = { script: scriptC };
+
+const runtimeFieldA = { runtimeField: { script: { source: scriptA } } };
+const runtimeFieldB = { runtimeField: { script: { source: scriptB } } };
+const runtimeFieldC = { runtimeField: { script: { source: scriptC } } };
+
+const indexPatterns = ({
+ getIds: async () => [1, 2, 3],
+ get: jest.fn().mockResolvedValue({
+ getScriptedFields: () => [],
+ fields: [],
+ }),
+} as any) as IndexPatternsCommonService;
+
+describe('index pattern usage collection', () => {
+ it('minMaxAvgLoC calculates min, max, and average ', () => {
+ const scripts = [scriptA, scriptB, scriptC];
+ expect(minMaxAvgLoC(scripts)).toEqual({ min: 1, max: 3, avg: 2 });
+ expect(minMaxAvgLoC([undefined, undefined, undefined])).toEqual({ min: 0, max: 0, avg: 0 });
+ });
+
+ it('updateMin returns minimum value', () => {
+ expect(updateMin(undefined, 1)).toEqual(1);
+ expect(updateMin(1, 0)).toEqual(0);
+ });
+
+ it('updateMax returns maximum value', () => {
+ expect(updateMax(undefined, 1)).toEqual(1);
+ expect(updateMax(1, 0)).toEqual(1);
+ });
+
+ describe('calculates index pattern usage', () => {
+ const countSummaryDefault = {
+ min: undefined,
+ max: undefined,
+ avg: undefined,
+ };
+
+ it('when there are no runtime fields or scripted fields', async () => {
+ expect(await getIndexPatternTelemetry(indexPatterns)).toEqual({
+ indexPatternsCount: 3,
+ indexPatternsWithScriptedFieldCount: 0,
+ indexPatternsWithRuntimeFieldCount: 0,
+ scriptedFieldCount: 0,
+ runtimeFieldCount: 0,
+ perIndexPattern: {
+ scriptedFieldCount: countSummaryDefault,
+ runtimeFieldCount: countSummaryDefault,
+ scriptedFieldLineCount: countSummaryDefault,
+ runtimeFieldLineCount: countSummaryDefault,
+ },
+ });
+ });
+
+ it('when there are both runtime fields or scripted fields', async () => {
+ indexPatterns.get = jest.fn().mockResolvedValue({
+ getScriptedFields: () => [scriptedFieldA, scriptedFieldB, scriptedFieldC],
+ fields: [runtimeFieldA, runtimeFieldB, runtimeFieldC],
+ });
+
+ expect(await getIndexPatternTelemetry(indexPatterns)).toEqual({
+ indexPatternsCount: 3,
+ indexPatternsWithScriptedFieldCount: 3,
+ indexPatternsWithRuntimeFieldCount: 3,
+ scriptedFieldCount: 9,
+ runtimeFieldCount: 9,
+ perIndexPattern: {
+ scriptedFieldCount: { min: 3, max: 3, avg: 3 },
+ runtimeFieldCount: { min: 3, max: 3, avg: 3 },
+ scriptedFieldLineCount: { min: 1, max: 3, avg: 2 },
+ runtimeFieldLineCount: { min: 1, max: 3, avg: 2 },
+ },
+ });
+ });
+
+ it('when there are only runtime fields', async () => {
+ indexPatterns.get = jest.fn().mockResolvedValue({
+ getScriptedFields: () => [],
+ fields: [runtimeFieldA, runtimeFieldB, runtimeFieldC],
+ });
+
+ expect(await getIndexPatternTelemetry(indexPatterns)).toEqual({
+ indexPatternsCount: 3,
+ indexPatternsWithScriptedFieldCount: 0,
+ indexPatternsWithRuntimeFieldCount: 3,
+ scriptedFieldCount: 0,
+ runtimeFieldCount: 9,
+ perIndexPattern: {
+ scriptedFieldCount: countSummaryDefault,
+ runtimeFieldCount: { min: 3, max: 3, avg: 3 },
+ scriptedFieldLineCount: countSummaryDefault,
+ runtimeFieldLineCount: { min: 1, max: 3, avg: 2 },
+ },
+ });
+ });
+
+ it('when there are only scripted fields', async () => {
+ indexPatterns.get = jest.fn().mockResolvedValue({
+ getScriptedFields: () => [scriptedFieldA, scriptedFieldB, scriptedFieldC],
+ fields: [],
+ });
+
+ expect(await getIndexPatternTelemetry(indexPatterns)).toEqual({
+ indexPatternsCount: 3,
+ indexPatternsWithScriptedFieldCount: 3,
+ indexPatternsWithRuntimeFieldCount: 0,
+ scriptedFieldCount: 9,
+ runtimeFieldCount: 0,
+ perIndexPattern: {
+ scriptedFieldCount: { min: 3, max: 3, avg: 3 },
+ runtimeFieldCount: countSummaryDefault,
+ scriptedFieldLineCount: { min: 1, max: 3, avg: 2 },
+ runtimeFieldLineCount: countSummaryDefault,
+ },
+ });
+ });
+ });
+});
diff --git a/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.ts b/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.ts
new file mode 100644
index 0000000000000..36c2a59ce2753
--- /dev/null
+++ b/src/plugins/data/server/index_patterns/register_index_pattern_usage_collection.ts
@@ -0,0 +1,193 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { UsageCollectionSetup } from 'src/plugins/usage_collection/server';
+import { StartServicesAccessor } from 'src/core/server';
+import { IndexPatternsCommonService } from '..';
+import { SavedObjectsClient } from '../../../../core/server';
+import { DataPluginStartDependencies, DataPluginStart } from '../plugin';
+
+interface CountSummary {
+ min?: number;
+ max?: number;
+ avg?: number;
+}
+
+interface IndexPatternUsage {
+ indexPatternsCount: number;
+ indexPatternsWithScriptedFieldCount: number;
+ indexPatternsWithRuntimeFieldCount: number;
+ scriptedFieldCount: number;
+ runtimeFieldCount: number;
+ perIndexPattern: {
+ scriptedFieldCount: CountSummary;
+ runtimeFieldCount: CountSummary;
+ scriptedFieldLineCount: CountSummary;
+ runtimeFieldLineCount: CountSummary;
+ };
+}
+
+export const minMaxAvgLoC = (scripts: Array) => {
+ const lengths = scripts.map((script) => script?.split(/\r\n|\r|\n/).length || 0).sort();
+ return {
+ min: lengths[0],
+ max: lengths[lengths.length - 1],
+ avg: lengths.reduce((col, count) => col + count, 0) / lengths.length,
+ };
+};
+
+export const updateMin = (currentMin: number | undefined, newVal: number): number => {
+ if (currentMin === undefined || currentMin > newVal) {
+ return newVal;
+ } else {
+ return currentMin;
+ }
+};
+
+export const updateMax = (currentMax: number | undefined, newVal: number): number => {
+ if (currentMax === undefined || currentMax < newVal) {
+ return newVal;
+ } else {
+ return currentMax;
+ }
+};
+
+export async function getIndexPatternTelemetry(indexPatterns: IndexPatternsCommonService) {
+ const ids = await indexPatterns.getIds();
+
+ const countSummaryDefaults: CountSummary = {
+ min: undefined,
+ max: undefined,
+ avg: undefined,
+ };
+
+ const results = {
+ indexPatternsCount: ids.length,
+ indexPatternsWithScriptedFieldCount: 0,
+ indexPatternsWithRuntimeFieldCount: 0,
+ scriptedFieldCount: 0,
+ runtimeFieldCount: 0,
+ perIndexPattern: {
+ scriptedFieldCount: { ...countSummaryDefaults },
+ runtimeFieldCount: { ...countSummaryDefaults },
+ scriptedFieldLineCount: { ...countSummaryDefaults },
+ runtimeFieldLineCount: { ...countSummaryDefaults },
+ },
+ };
+
+ await ids.reduce(async (col, id) => {
+ await col;
+ const ip = await indexPatterns.get(id);
+
+ const scriptedFields = ip.getScriptedFields();
+ const runtimeFields = ip.fields.filter((fld) => !!fld.runtimeField);
+
+ if (scriptedFields.length > 0) {
+ // increment counts
+ results.indexPatternsWithScriptedFieldCount++;
+ results.scriptedFieldCount += scriptedFields.length;
+
+ // calc LoC
+ results.perIndexPattern.scriptedFieldLineCount = minMaxAvgLoC(
+ scriptedFields.map((fld) => fld.script || '')
+ );
+
+ // calc field counts
+ results.perIndexPattern.scriptedFieldCount.min = updateMin(
+ results.perIndexPattern.scriptedFieldCount.min,
+ scriptedFields.length
+ );
+ results.perIndexPattern.scriptedFieldCount.max = updateMax(
+ results.perIndexPattern.scriptedFieldCount.max,
+ scriptedFields.length
+ );
+ results.perIndexPattern.scriptedFieldCount.avg =
+ results.scriptedFieldCount / results.indexPatternsWithScriptedFieldCount;
+ }
+
+ if (runtimeFields.length > 0) {
+ // increment counts
+ results.indexPatternsWithRuntimeFieldCount++;
+ results.runtimeFieldCount += runtimeFields.length;
+
+ // calc LoC
+ const runtimeFieldScripts = runtimeFields.map(
+ (fld) => fld.runtimeField?.script?.source || ''
+ );
+ results.perIndexPattern.runtimeFieldLineCount = minMaxAvgLoC(runtimeFieldScripts);
+
+ // calc field counts
+ results.perIndexPattern.runtimeFieldCount.min = updateMin(
+ results.perIndexPattern.runtimeFieldCount.min,
+ runtimeFields.length
+ );
+ results.perIndexPattern.runtimeFieldCount.max = updateMax(
+ results.perIndexPattern.runtimeFieldCount.max,
+ runtimeFields.length
+ );
+ results.perIndexPattern.runtimeFieldCount.avg =
+ results.runtimeFieldCount / results.indexPatternsWithRuntimeFieldCount;
+ }
+ }, Promise.resolve());
+
+ return results;
+}
+
+export function registerIndexPatternsUsageCollector(
+ getStartServices: StartServicesAccessor,
+ usageCollection?: UsageCollectionSetup
+): void {
+ if (!usageCollection) {
+ return;
+ }
+
+ const indexPatternUsageCollector = usageCollection.makeUsageCollector({
+ type: 'index-patterns',
+ isReady: () => true,
+ fetch: async () => {
+ const [{ savedObjects, elasticsearch }, , { indexPatterns }] = await getStartServices();
+ const indexPatternService = await indexPatterns.indexPatternsServiceFactory(
+ new SavedObjectsClient(savedObjects.createInternalRepository()),
+ elasticsearch.client.asInternalUser
+ );
+
+ return await getIndexPatternTelemetry(indexPatternService);
+ },
+ schema: {
+ indexPatternsCount: { type: 'long' },
+ indexPatternsWithScriptedFieldCount: { type: 'long' },
+ indexPatternsWithRuntimeFieldCount: { type: 'long' },
+ scriptedFieldCount: { type: 'long' },
+ runtimeFieldCount: { type: 'long' },
+ perIndexPattern: {
+ scriptedFieldCount: {
+ min: { type: 'long' },
+ max: { type: 'long' },
+ avg: { type: 'float' },
+ },
+ runtimeFieldCount: {
+ min: { type: 'long' },
+ max: { type: 'long' },
+ avg: { type: 'float' },
+ },
+ scriptedFieldLineCount: {
+ min: { type: 'long' },
+ max: { type: 'long' },
+ avg: { type: 'float' },
+ },
+ runtimeFieldLineCount: {
+ min: { type: 'long' },
+ max: { type: 'long' },
+ avg: { type: 'float' },
+ },
+ },
+ },
+ });
+
+ usageCollection.registerCollector(indexPatternUsageCollector);
+}
diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts
index a7a7663d6981c..7b73802f1a34d 100644
--- a/src/plugins/data/server/plugin.ts
+++ b/src/plugins/data/server/plugin.ts
@@ -46,8 +46,10 @@ export interface DataPluginSetupDependencies {
usageCollection?: UsageCollectionSetup;
}
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export interface DataPluginStartDependencies {}
+export interface DataPluginStartDependencies {
+ fieldFormats: FieldFormatsStart;
+ logger: Logger;
+}
export class DataServerPlugin
implements
@@ -82,7 +84,11 @@ export class DataServerPlugin
this.queryService.setup(core);
this.autocompleteService.setup(core);
this.kqlTelemetryService.setup(core, { usageCollection });
- this.indexPatterns.setup(core, { expressions });
+ this.indexPatterns.setup(core, {
+ expressions,
+ logger: this.logger.get('indexPatterns'),
+ usageCollection,
+ });
core.uiSettings.register(getUiSettings());
diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts
index 192c133c94a04..d5a83efcc215f 100644
--- a/src/plugins/data/server/search/search_service.test.ts
+++ b/src/plugins/data/server/search/search_service.test.ts
@@ -10,7 +10,7 @@ import type { MockedKeys } from '@kbn/utility-types/jest';
import { CoreSetup, CoreStart, SavedObject } from '../../../../core/server';
import { coreMock } from '../../../../core/server/mocks';
-import { DataPluginStart } from '../plugin';
+import { DataPluginStart, DataPluginStartDependencies } from '../plugin';
import { createFieldFormatsStartMock } from '../field_formats/mocks';
import { createIndexPatternsStartMock } from '../index_patterns/mocks';
@@ -32,7 +32,7 @@ import { createSearchSessionsClientMock } from './mocks';
describe('Search service', () => {
let plugin: SearchService;
- let mockCoreSetup: MockedKeys>;
+ let mockCoreSetup: MockedKeys>;
let mockCoreStart: MockedKeys;
beforeEach(() => {
diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts
index b62c5d26f691d..e53244fa7ff26 100644
--- a/src/plugins/data/server/search/search_service.ts
+++ b/src/plugins/data/server/search/search_service.ts
@@ -38,7 +38,7 @@ import { FieldFormatsStart } from '../field_formats';
import { IndexPatternsServiceStart } from '../index_patterns';
import { getCallMsearch, registerMsearchRoute, registerSearchRoute } from './routes';
import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search';
-import { DataPluginStart } from '../plugin';
+import { DataPluginStart, DataPluginStartDependencies } from '../plugin';
import { UsageCollectionSetup } from '../../../usage_collection/server';
import { registerUsageCollector } from './collectors/register';
import { usageProvider } from './collectors/usage';
@@ -114,7 +114,7 @@ export class SearchService implements Plugin {
}
public setup(
- core: CoreSetup<{}, DataPluginStart>,
+ core: CoreSetup,
{ bfetch, expressions, usageCollection }: SearchServiceSetupDependencies
): ISearchSetup {
const usage = usageCollection ? usageProvider(core) : undefined;
diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md
index 1f043cc9aab4e..29a5a67239171 100644
--- a/src/plugins/data/server/server.api.md
+++ b/src/plugins/data/server/server.api.md
@@ -73,6 +73,7 @@ import { Type } from '@kbn/config-schema';
import { TypeOf } from '@kbn/config-schema';
import { UiCounterMetricType } from '@kbn/analytics';
import { Unit } from '@elastic/datemath';
+import { UsageCollectionSetup as UsageCollectionSetup_2 } from 'src/plugins/usage_collection/server';
// Warning: (ae-forgotten-export) The symbol "AggConfigSerialized" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "AggConfigOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
@@ -958,16 +959,14 @@ export { IndexPatternsService }
//
// @public (undocumented)
export class IndexPatternsServiceProvider implements Plugin_3 {
- // Warning: (ae-forgotten-export) The symbol "DataPluginStartDependencies" needs to be exported by the entry point index.d.ts
+ // Warning: (ae-forgotten-export) The symbol "IndexPatternsServiceStartDeps" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "IndexPatternsServiceSetupDeps" needs to be exported by the entry point index.d.ts
//
// (undocumented)
- setup(core: CoreSetup_2, { expressions }: IndexPatternsServiceSetupDeps): void;
- // Warning: (ae-forgotten-export) The symbol "IndexPatternsServiceStartDeps" needs to be exported by the entry point index.d.ts
- //
+ setup(core: CoreSetup_2, { expressions, usageCollection }: IndexPatternsServiceSetupDeps): void;
// (undocumented)
start(core: CoreStart, { fieldFormats, logger }: IndexPatternsServiceStartDeps): {
- indexPatternsServiceFactory: (savedObjectsClient: SavedObjectsClientContract_2, elasticsearchClient: ElasticsearchClient_2) => Promise;
+ indexPatternsServiceFactory: (savedObjectsClient: Pick, elasticsearchClient: ElasticsearchClient_2) => Promise;
};
}
@@ -1213,6 +1212,7 @@ export type ParsedInterval = ReturnType;
export function parseInterval(interval: string): moment.Duration | null;
// Warning: (ae-forgotten-export) The symbol "DataPluginSetupDependencies" needs to be exported by the entry point index.d.ts
+// Warning: (ae-forgotten-export) The symbol "DataPluginStartDependencies" needs to be exported by the entry point index.d.ts
// Warning: (ae-missing-release-tag) "DataServerPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
@@ -1522,7 +1522,7 @@ export function usageProvider(core: CoreSetup_2): SearchUsage;
// src/plugins/data/server/index.ts:267:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:270:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/index.ts:271:1 - (ae-forgotten-export) The symbol "calcAutoIntervalLessThan" needs to be exported by the entry point index.d.ts
-// src/plugins/data/server/plugin.ts:79:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
+// src/plugins/data/server/plugin.ts:81:74 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts
// src/plugins/data/server/search/types.ts:114:5 - (ae-forgotten-export) The symbol "ISearchStartSearchSource" needs to be exported by the entry point index.d.ts
// (No @packageDocumentation comment for this package)
diff --git a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
index fa0a32fc3d542..0054bb9c01b41 100644
--- a/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
+++ b/src/plugins/kibana_react/public/table_list_view/table_list_view.tsx
@@ -347,20 +347,6 @@ class TableListView extends React.Component
- );
- }
- }
-
renderToolsLeft() {
const selection = this.state.selectedIds;
@@ -473,10 +459,9 @@ class TableListView extends React.Component void;
onSave: (props: OnSaveProps & { dashboardId: string | null; addToLibrary: boolean }) => void;
@@ -35,7 +36,7 @@ export interface SaveModalDashboardProps {
}
export function SavedObjectSaveModalDashboard(props: SaveModalDashboardProps) {
- const { documentInfo, tagOptions, objectType, onClose } = props;
+ const { documentInfo, tagOptions, objectType, onClose, canSaveByReference } = props;
const { id: documentId } = documentInfo;
const initialCopyOnSave = !Boolean(documentId);
@@ -49,7 +50,7 @@ export function SavedObjectSaveModalDashboard(props: SaveModalDashboardProps) {
documentId || disableDashboardOptions ? null : 'existing'
);
const [isAddToLibrarySelected, setAddToLibrary] = useState(
- !initialCopyOnSave || disableDashboardOptions
+ canSaveByReference && (!initialCopyOnSave || disableDashboardOptions)
);
const [selectedDashboard, setSelectedDashboard] = useState<{ id: string; name: string } | null>(
null
@@ -65,13 +66,16 @@ export function SavedObjectSaveModalDashboard(props: SaveModalDashboardProps) {
onChange={(option) => {
setDashboardOption(option);
}}
+ canSaveByReference={canSaveByReference}
{...{ copyOnSave, documentId, dashboardOption, setAddToLibrary, isAddToLibrarySelected }}
/>
)
: null;
const onCopyOnSaveChange = (newCopyOnSave: boolean) => {
- setAddToLibrary(true);
+ if (canSaveByReference) {
+ setAddToLibrary(true);
+ }
setDashboardOption(null);
setCopyOnSave(newCopyOnSave);
};
diff --git a/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.stories.tsx b/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.stories.tsx
index dd6fd975f8e07..341f194b71ba4 100644
--- a/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.stories.tsx
+++ b/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.stories.tsx
@@ -33,15 +33,21 @@ export default {
control: 'boolean',
defaultValue: true,
},
+ canSaveVisualizations: {
+ control: 'boolean',
+ defaultValue: true,
+ },
},
};
export function Example({
copyOnSave,
hasDocumentId,
+ canSaveVisualizations,
}: {
copyOnSave: boolean;
hasDocumentId: boolean;
+ canSaveVisualizations: boolean;
} & StorybookParams) {
const [dashboardOption, setDashboardOption] = useState<'new' | 'existing' | null>('existing');
const [isAddToLibrarySelected, setAddToLibrary] = useState(false);
@@ -52,6 +58,7 @@ export function Example({
onChange={setDashboardOption}
dashboardOption={dashboardOption}
copyOnSave={copyOnSave}
+ canSaveByReference={canSaveVisualizations}
documentId={hasDocumentId ? 'abc' : undefined}
isAddToLibrarySelected={isAddToLibrarySelected}
setAddToLibrary={setAddToLibrary}
diff --git a/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.tsx b/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.tsx
index 1ae54040571a2..78a1569c02ead 100644
--- a/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.tsx
+++ b/src/plugins/presentation_util/public/components/saved_object_save_modal_dashboard_selector.tsx
@@ -30,6 +30,7 @@ export interface SaveModalDashboardSelectorProps {
copyOnSave: boolean;
documentId?: string;
onSelectDashboard: DashboardPickerProps['onChange'];
+ canSaveByReference: boolean;
setAddToLibrary: (selected: boolean) => void;
isAddToLibrarySelected: boolean;
dashboardOption: 'new' | 'existing' | null;
@@ -40,6 +41,7 @@ export function SaveModalDashboardSelector(props: SaveModalDashboardSelectorProp
const {
documentId,
onSelectDashboard,
+ canSaveByReference,
setAddToLibrary,
isAddToLibrarySelected,
dashboardOption,
@@ -114,7 +116,7 @@ export function SaveModalDashboardSelector(props: SaveModalDashboardSelectorProp
setAddToLibrary(true);
onChange(null);
}}
- disabled={isDisabled}
+ disabled={isDisabled || !canSaveByReference}
/>
@@ -127,7 +129,7 @@ export function SaveModalDashboardSelector(props: SaveModalDashboardSelectorProp
defaultMessage: 'Add to library',
})}
checked={isAddToLibrarySelected}
- disabled={dashboardOption === null || isDisabled}
+ disabled={dashboardOption === null || isDisabled || !canSaveByReference}
onChange={(event) => setAddToLibrary(event.target.checked)}
/>
diff --git a/src/plugins/presentation_util/public/services/index.ts b/src/plugins/presentation_util/public/services/index.ts
index 74607b9e35e47..39dae92aa2ba9 100644
--- a/src/plugins/presentation_util/public/services/index.ts
+++ b/src/plugins/presentation_util/public/services/index.ts
@@ -23,6 +23,7 @@ export interface PresentationDashboardsService {
export interface PresentationCapabilitiesService {
canAccessDashboards: () => boolean;
canCreateNewDashboards: () => boolean;
+ canSaveVisualizations: () => boolean;
}
export interface PresentationUtilServices {
diff --git a/src/plugins/presentation_util/public/services/kibana/capabilities.ts b/src/plugins/presentation_util/public/services/kibana/capabilities.ts
index 546281d083f2f..6949fba00c65a 100644
--- a/src/plugins/presentation_util/public/services/kibana/capabilities.ts
+++ b/src/plugins/presentation_util/public/services/kibana/capabilities.ts
@@ -16,10 +16,11 @@ export type CapabilitiesServiceFactory = KibanaPluginServiceFactory<
>;
export const capabilitiesServiceFactory: CapabilitiesServiceFactory = ({ coreStart }) => {
- const { dashboard } = coreStart.application.capabilities;
+ const { dashboard, visualize } = coreStart.application.capabilities;
return {
canAccessDashboards: () => Boolean(dashboard.show),
canCreateNewDashboards: () => Boolean(dashboard.createNew),
+ canSaveVisualizations: () => Boolean(visualize.save),
};
};
diff --git a/src/plugins/presentation_util/public/services/storybook/capabilities.ts b/src/plugins/presentation_util/public/services/storybook/capabilities.ts
index fcd38b29f154c..16fbe3baf488f 100644
--- a/src/plugins/presentation_util/public/services/storybook/capabilities.ts
+++ b/src/plugins/presentation_util/public/services/storybook/capabilities.ts
@@ -19,11 +19,13 @@ export const capabilitiesServiceFactory: CapabilitiesServiceFactory = ({
canAccessDashboards,
canCreateNewDashboards,
canEditDashboards,
+ canSaveVisualizations,
}) => {
const check = (value: boolean = true) => value;
return {
canAccessDashboards: () => check(canAccessDashboards),
canCreateNewDashboards: () => check(canCreateNewDashboards),
canEditDashboards: () => check(canEditDashboards),
+ canSaveVisualizations: () => check(canSaveVisualizations),
};
};
diff --git a/src/plugins/presentation_util/public/services/storybook/index.ts b/src/plugins/presentation_util/public/services/storybook/index.ts
index 37b2171635e96..dd7de54264062 100644
--- a/src/plugins/presentation_util/public/services/storybook/index.ts
+++ b/src/plugins/presentation_util/public/services/storybook/index.ts
@@ -18,6 +18,7 @@ export interface StorybookParams {
canAccessDashboards?: boolean;
canCreateNewDashboards?: boolean;
canEditDashboards?: boolean;
+ canSaveVisualizations?: boolean;
}
export const providers: PluginServiceProviders = {
diff --git a/src/plugins/presentation_util/public/services/stub/capabilities.ts b/src/plugins/presentation_util/public/services/stub/capabilities.ts
index 979ccc8faadd5..4154fa65a0cd7 100644
--- a/src/plugins/presentation_util/public/services/stub/capabilities.ts
+++ b/src/plugins/presentation_util/public/services/stub/capabilities.ts
@@ -15,4 +15,5 @@ export const capabilitiesServiceFactory: CapabilitiesServiceFactory = () => ({
canAccessDashboards: () => true,
canCreateNewDashboards: () => true,
canEditDashboards: () => true,
+ canSaveVisualizations: () => true,
});
diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json
index 0ce727830ffdd..05ac1eb84089d 100644
--- a/src/plugins/telemetry/schema/oss_plugins.json
+++ b/src/plugins/telemetry/schema/oss_plugins.json
@@ -24,6 +24,81 @@
}
}
},
+ "index-patterns": {
+ "properties": {
+ "indexPatternsCount": {
+ "type": "long"
+ },
+ "indexPatternsWithScriptedFieldCount": {
+ "type": "long"
+ },
+ "indexPatternsWithRuntimeFieldCount": {
+ "type": "long"
+ },
+ "scriptedFieldCount": {
+ "type": "long"
+ },
+ "runtimeFieldCount": {
+ "type": "long"
+ },
+ "perIndexPattern": {
+ "properties": {
+ "scriptedFieldCount": {
+ "properties": {
+ "min": {
+ "type": "long"
+ },
+ "max": {
+ "type": "long"
+ },
+ "avg": {
+ "type": "float"
+ }
+ }
+ },
+ "runtimeFieldCount": {
+ "properties": {
+ "min": {
+ "type": "long"
+ },
+ "max": {
+ "type": "long"
+ },
+ "avg": {
+ "type": "float"
+ }
+ }
+ },
+ "scriptedFieldLineCount": {
+ "properties": {
+ "min": {
+ "type": "long"
+ },
+ "max": {
+ "type": "long"
+ },
+ "avg": {
+ "type": "float"
+ }
+ }
+ },
+ "runtimeFieldLineCount": {
+ "properties": {
+ "min": {
+ "type": "long"
+ },
+ "max": {
+ "type": "long"
+ },
+ "avg": {
+ "type": "float"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"kql": {
"properties": {
"optInCount": {
diff --git a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts
index 989a9bf5d2cb7..e2e2a4c089270 100644
--- a/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts
+++ b/src/plugins/visualizations/public/embeddable/create_vis_embeddable_from_object.ts
@@ -67,7 +67,10 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe
indexPatterns = [vis.data.indexPattern];
}
- const editable = getCapabilities().visualize.save as boolean;
+ const capabilities = {
+ visualizeSave: Boolean(getCapabilities().visualize.save),
+ dashboardSave: Boolean(getCapabilities().dashboard?.showWriteControls),
+ };
return new VisualizeEmbeddable(
getTimeFilter(),
@@ -76,8 +79,8 @@ export const createVisEmbeddableFromObject = (deps: VisualizeEmbeddableFactoryDe
indexPatterns,
editPath,
editUrl,
- editable,
deps,
+ capabilities,
},
input,
attributeService,
diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
index 580ffef548fe1..429dabeeef042 100644
--- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
+++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.ts
@@ -50,7 +50,7 @@ export interface VisualizeEmbeddableConfiguration {
indexPatterns?: IIndexPattern[];
editPath: string;
editUrl: string;
- editable: boolean;
+ capabilities: { visualizeSave: boolean; dashboardSave: boolean };
deps: VisualizeEmbeddableFactoryDeps;
}
@@ -111,7 +111,7 @@ export class VisualizeEmbeddable
constructor(
timefilter: TimefilterContract,
- { vis, editPath, editUrl, indexPatterns, editable, deps }: VisualizeEmbeddableConfiguration,
+ { vis, editPath, editUrl, indexPatterns, deps, capabilities }: VisualizeEmbeddableConfiguration,
initialInput: VisualizeInput,
attributeService?: AttributeService<
VisualizeSavedObjectAttributes,
@@ -129,7 +129,6 @@ export class VisualizeEmbeddable
editApp: 'visualize',
editUrl,
indexPatterns,
- editable,
visTypeName: vis.type.name,
},
parent
@@ -143,6 +142,12 @@ export class VisualizeEmbeddable
this.attributeService = attributeService;
this.savedVisualizationsLoader = savedVisualizationsLoader;
+ if (this.attributeService) {
+ const isByValue = !this.inputIsRefType(initialInput);
+ const editable = capabilities.visualizeSave || (isByValue && capabilities.dashboardSave);
+ this.updateOutput({ ...this.getOutput(), editable });
+ }
+
this.subscriptions.push(
this.getUpdated$().subscribe(() => {
const isDirty = this.handleChanges();
diff --git a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx
index 4f5679a14b0b7..e696bcb5dbe4d 100644
--- a/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx
+++ b/src/plugins/visualize/public/application/utils/get_top_nav_config.tsx
@@ -82,6 +82,7 @@ export const getTopNavConfig = (
setActiveUrl,
toastNotifications,
visualizeCapabilities,
+ dashboardCapabilities,
i18n: { Context: I18nContext },
dashboard,
savedObjectsTagging,
@@ -205,9 +206,9 @@ export const getTopNavConfig = (
}
};
+ const allowByValue = dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables;
const saveButtonLabel =
- embeddableId ||
- (!savedVis.id && dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables && originatingApp)
+ embeddableId || (!savedVis.id && allowByValue && originatingApp)
? i18n.translate('visualize.topNavMenu.saveVisualizationToLibraryButtonLabel', {
defaultMessage: 'Save to library',
})
@@ -219,9 +220,11 @@ export const getTopNavConfig = (
defaultMessage: 'Save',
});
- const showSaveAndReturn =
- originatingApp &&
- (savedVis?.id || dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables);
+ const showSaveAndReturn = originatingApp && (savedVis?.id || allowByValue);
+
+ const showSaveButton =
+ visualizeCapabilities.save ||
+ (allowByValue && !showSaveAndReturn && dashboardCapabilities.showWriteControls);
const topNavMenu: TopNavMenuData[] = [
{
@@ -300,7 +303,7 @@ export const getTopNavConfig = (
},
]
: []),
- ...(visualizeCapabilities.save
+ ...(showSaveButton
? [
{
id: 'save',
@@ -439,7 +442,12 @@ export const getTopNavConfig = (
/>
) : (
{
defaultMessage: 'Read only',
}),
tooltip: i18n.translate('visualize.badge.readOnly.tooltip', {
- defaultMessage: 'Unable to save visualizations',
+ defaultMessage: 'Unable to save visualizations to the library',
}),
iconType: 'glasses',
});
diff --git a/tsconfig.json b/tsconfig.json
index 14b373815584b..03597114333ca 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -195,6 +195,7 @@
{ "path": "./x-pack/plugins/stack_alerts/tsconfig.json" },
{ "path": "./x-pack/plugins/task_manager/tsconfig.json" },
{ "path": "./x-pack/plugins/telemetry_collection_xpack/tsconfig.json" },
+ { "path": "./x-pack/plugins/timelines/tsconfig.json" },
{ "path": "./x-pack/plugins/transform/tsconfig.json" },
{ "path": "./x-pack/plugins/translations/tsconfig.json" },
{ "path": "./x-pack/plugins/triggers_actions_ui/tsconfig.json" },
diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json
index 663ae32f9128a..6bbbf6cd6b82d 100644
--- a/x-pack/.i18nrc.json
+++ b/x-pack/.i18nrc.json
@@ -53,6 +53,7 @@
"xpack.spaces": "plugins/spaces",
"xpack.savedObjectsTagging": ["plugins/saved_objects_tagging"],
"xpack.taskManager": "legacy/plugins/task_manager",
+ "xpack.timelines": "plugins/timelines",
"xpack.transform": "plugins/transform",
"xpack.triggersActionsUI": "plugins/triggers_actions_ui",
"xpack.upgradeAssistant": "plugins/upgrade_assistant",
diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json
index a9a0149e72ce7..e340f8bf19126 100644
--- a/x-pack/plugins/apm/kibana.json
+++ b/x-pack/plugins/apm/kibana.json
@@ -12,6 +12,7 @@
"infra"
],
"optionalPlugins": [
+ "spaces",
"cloud",
"usageCollection",
"taskManager",
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
index ef67501ec761b..1e368b2eb5368 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/EmbeddedMap.tsx
@@ -24,7 +24,7 @@ import {
import { useLayerList } from './useLayerList';
import { useUrlParams } from '../../../../context/url_params_context/use_url_params';
import { useApmPluginContext } from '../../../../context/apm_plugin/use_apm_plugin_context';
-import { RenderTooltipContentParams } from '../../../../../../maps/public';
+import type { RenderTooltipContentParams } from '../../../../../../maps/public';
import { MapToolTip } from './MapToolTip';
import { useMapFilters } from './useMapFilters';
import { EmbeddableStart } from '../../../../../../../../src/plugins/embeddable/public';
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/MapToolTip.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/MapToolTip.tsx
index 7e6c8ddd493bf..7501d5bfaa2c5 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/MapToolTip.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/MapToolTip.tsx
@@ -20,7 +20,7 @@ import {
TRANSACTION_DURATION_COUNTRY,
TRANSACTION_DURATION_REGION,
} from './useLayerList';
-import { RenderTooltipContentParams } from '../../../../../../maps/public';
+import type { RenderTooltipContentParams } from '../../../../../../maps/public';
import { I18LABELS } from '../translations';
type MapToolTipProps = Partial;
diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts
index 1c33fcbd71dac..19163da449b90 100644
--- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts
+++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.test.ts
@@ -36,7 +36,12 @@ describe('createStaticIndexPattern', () => {
'xpack.apm.autocreateApmIndexPattern': false,
});
const savedObjectsClient = getMockSavedObjectsClient();
- await createStaticIndexPattern(setup, context, savedObjectsClient);
+ await createStaticIndexPattern(
+ setup,
+ context,
+ savedObjectsClient,
+ 'default'
+ );
expect(savedObjectsClient.create).not.toHaveBeenCalled();
});
@@ -53,7 +58,12 @@ describe('createStaticIndexPattern', () => {
const savedObjectsClient = getMockSavedObjectsClient();
- await createStaticIndexPattern(setup, context, savedObjectsClient);
+ await createStaticIndexPattern(
+ setup,
+ context,
+ savedObjectsClient,
+ 'default'
+ );
expect(savedObjectsClient.create).not.toHaveBeenCalled();
});
@@ -70,7 +80,12 @@ describe('createStaticIndexPattern', () => {
const savedObjectsClient = getMockSavedObjectsClient();
- await createStaticIndexPattern(setup, context, savedObjectsClient);
+ await createStaticIndexPattern(
+ setup,
+ context,
+ savedObjectsClient,
+ 'default'
+ );
expect(savedObjectsClient.create).toHaveBeenCalled();
});
diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
index 0b7f82c0b8388..b91fb8342a212 100644
--- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
+++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
@@ -20,7 +20,8 @@ import { getApmIndexPatternTitle } from './get_apm_index_pattern_title';
export async function createStaticIndexPattern(
setup: Setup,
context: APMRequestHandlerContext,
- savedObjectsClient: InternalSavedObjectsClient
+ savedObjectsClient: InternalSavedObjectsClient,
+ spaceId: string | undefined
): Promise {
return withApmSpan('create_static_index_pattern', async () => {
const { config } = context;
@@ -46,7 +47,11 @@ export async function createStaticIndexPattern(
...apmIndexPattern.attributes,
title: apmIndexPatternTitle,
},
- { id: APM_STATIC_INDEX_PATTERN_ID, overwrite: false }
+ {
+ id: APM_STATIC_INDEX_PATTERN_ID,
+ overwrite: false,
+ namespace: spaceId,
+ }
)
);
return true;
diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts
index f556374179c51..db96794627519 100644
--- a/x-pack/plugins/apm/server/plugin.ts
+++ b/x-pack/plugins/apm/server/plugin.ts
@@ -16,6 +16,7 @@ import {
Plugin,
PluginInitializerContext,
} from 'src/core/server';
+import { SpacesPluginSetup } from '../../spaces/server';
import { APMConfig, APMXPackConfig } from '.';
import { mergeConfigs } from './index';
import { APMOSSPluginSetup } from '../../../../src/plugins/apm_oss/server';
@@ -65,6 +66,7 @@ export class APMPlugin implements Plugin {
public setup(
core: CoreSetup,
plugins: {
+ spaces?: SpacesPluginSetup;
apmOss: APMOSSPluginSetup;
home: HomeServerPluginSetup;
licensing: LicensingPluginSetup;
@@ -148,11 +150,7 @@ export class APMPlugin implements Plugin {
createApmApi().init(core, {
config$: mergedConfig$,
logger: this.logger!,
- plugins: {
- observability: plugins.observability,
- security: plugins.security,
- ml: plugins.ml,
- },
+ plugins,
});
const boundGetApmIndices = async () =>
diff --git a/x-pack/plugins/apm/server/routes/index_pattern.ts b/x-pack/plugins/apm/server/routes/index_pattern.ts
index fd7d2120ab6f5..3b800c23135ce 100644
--- a/x-pack/plugins/apm/server/routes/index_pattern.ts
+++ b/x-pack/plugins/apm/server/routes/index_pattern.ts
@@ -21,10 +21,13 @@ export const staticIndexPatternRoute = createRoute((core) => ({
getInternalSavedObjectsClient(core),
]);
+ const spaceId = context.plugins.spaces?.spacesService.getSpaceId(request);
+
const didCreateIndexPattern = await createStaticIndexPattern(
setup,
context,
- savedObjectsClient
+ savedObjectsClient,
+ spaceId
);
return { created: didCreateIndexPattern };
diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts
index 1575041fb2f45..3ba24b4ed5268 100644
--- a/x-pack/plugins/apm/server/routes/typings.ts
+++ b/x-pack/plugins/apm/server/routes/typings.ts
@@ -14,6 +14,7 @@ import {
} from 'src/core/server';
import { Observable } from 'rxjs';
import { RequiredKeys, DeepPartial } from 'utility-types';
+import { SpacesPluginStart } from '../../../spaces/server';
import { ObservabilityPluginSetup } from '../../../observability/server';
import { LicensingApiRequestHandlerContext } from '../../../licensing/server';
import { SecurityPluginSetup } from '../../../security/server';
@@ -93,6 +94,7 @@ export type APMRequestHandlerContext<
config: APMConfig;
logger: Logger;
plugins: {
+ spaces?: SpacesPluginStart;
observability?: ObservabilityPluginSetup;
security?: SecurityPluginSetup;
ml?: MlPluginSetup;
diff --git a/x-pack/plugins/canvas/scripts/shareable_runtime.js b/x-pack/plugins/canvas/scripts/shareable_runtime.js
index 7f7f6d235c984..b760a92811b8e 100644
--- a/x-pack/plugins/canvas/scripts/shareable_runtime.js
+++ b/x-pack/plugins/canvas/scripts/shareable_runtime.js
@@ -56,7 +56,7 @@ run(
'webpack-dev-server',
'--config',
webpackConfig,
- ...(process.stdout.isTTY ? ['--progress'] : []),
+ ...(process.stdout.isTTY && !process.env.CI ? ['--progress'] : []),
'--hide-modules',
'--display-entrypoints',
'false',
@@ -93,7 +93,7 @@ run(
'--config',
webpackConfig,
'--hide-modules',
- ...(process.stdout.isTTY ? ['--progress'] : []),
+ ...(process.stdout.isTTY && !process.env.CI ? ['--progress'] : []),
],
{
...options,
diff --git a/x-pack/plugins/canvas/scripts/storybook.js b/x-pack/plugins/canvas/scripts/storybook.js
index 88af1cf6d38bb..e6b8a66b9026f 100644
--- a/x-pack/plugins/canvas/scripts/storybook.js
+++ b/x-pack/plugins/canvas/scripts/storybook.js
@@ -44,7 +44,7 @@ run(
'webpack',
'--config',
'x-pack/plugins/canvas/storybook/webpack.dll.config.js',
- '--progress',
+ ...(process.stdout.isTTY && !process.env.CI ? ['--progress'] : []),
'--hide-modules',
'--display-entrypoints',
'false',
diff --git a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts
index de16f6555d4bd..0eb392e784334 100644
--- a/x-pack/plugins/fleet/server/collectors/agent_collectors.ts
+++ b/x-pack/plugins/fleet/server/collectors/agent_collectors.ts
@@ -13,10 +13,11 @@ import * as AgentService from '../services/agents';
import { isFleetServerSetup } from '../services/fleet_server';
export interface AgentUsage {
- total: number;
- online: number;
- error: number;
+ total_enrolled: number;
+ healthy: number;
+ unhealthy: number;
offline: number;
+ total_all_statuses: number;
}
export const getAgentUsage = async (
@@ -27,21 +28,26 @@ export const getAgentUsage = async (
// TODO: unsure if this case is possible at all.
if (!soClient || !esClient || !(await isFleetServerSetup())) {
return {
- total: 0,
- online: 0,
- error: 0,
+ total_enrolled: 0,
+ healthy: 0,
+ unhealthy: 0,
offline: 0,
+ total_all_statuses: 0,
};
}
- const { total, online, error, offline } = await AgentService.getAgentStatusForAgentPolicy(
- soClient,
- esClient
- );
- return {
+ const {
total,
+ inactive,
online,
error,
offline,
+ } = await AgentService.getAgentStatusForAgentPolicy(soClient, esClient);
+ return {
+ total_enrolled: total,
+ healthy: online,
+ unhealthy: error,
+ offline,
+ total_all_statuses: total + inactive,
};
};
diff --git a/x-pack/plugins/fleet/server/collectors/register.ts b/x-pack/plugins/fleet/server/collectors/register.ts
index 7992d54d1dfad..842bb95fe813f 100644
--- a/x-pack/plugins/fleet/server/collectors/register.ts
+++ b/x-pack/plugins/fleet/server/collectors/register.ts
@@ -49,10 +49,36 @@ export function registerFleetUsageCollector(
schema: {
agents_enabled: { type: 'boolean' },
agents: {
- total: { type: 'long' },
- online: { type: 'long' },
- error: { type: 'long' },
- offline: { type: 'long' },
+ total_enrolled: {
+ type: 'long',
+ _meta: {
+ description: 'The total number of enrolled agents, in any state',
+ },
+ },
+ healthy: {
+ type: 'long',
+ _meta: {
+ description: 'The total number of enrolled agents in a healthy state',
+ },
+ },
+ unhealthy: {
+ type: 'long',
+ _meta: {
+ description: 'The total number of enrolled agents in an unhealthy state',
+ },
+ },
+ offline: {
+ type: 'long',
+ _meta: {
+ description: 'The total number of enrolled agents currently offline',
+ },
+ },
+ total_all_statuses: {
+ type: 'long',
+ _meta: {
+ description: 'The total number of agents in any state, both enrolled and inactive',
+ },
+ },
},
packages: {
type: 'array',
diff --git a/x-pack/plugins/fleet/server/services/agents/status.ts b/x-pack/plugins/fleet/server/services/agents/status.ts
index f3fb01655974e..737b6874a8133 100644
--- a/x-pack/plugins/fleet/server/services/agents/status.ts
+++ b/x-pack/plugins/fleet/server/services/agents/status.ts
@@ -55,17 +55,18 @@ export async function getAgentStatusForAgentPolicy(
agentPolicyId?: string,
filterKuery?: string
) {
- const [all, online, error, offline, updating] = await pMap(
+ const [all, allActive, online, error, offline, updating] = await pMap(
[
- undefined,
+ undefined, // All agents, including inactive
+ undefined, // All active agents
AgentStatusKueryHelper.buildKueryForOnlineAgents(),
AgentStatusKueryHelper.buildKueryForErrorAgents(),
AgentStatusKueryHelper.buildKueryForOfflineAgents(),
AgentStatusKueryHelper.buildKueryForUpdatingAgents(),
],
- (kuery) =>
+ (kuery, index) =>
getAgentsByKuery(esClient, {
- showInactive: false,
+ showInactive: index === 0,
perPage: 0,
page: 1,
kuery: joinKuerys(
@@ -84,7 +85,8 @@ export async function getAgentStatusForAgentPolicy(
return {
events: await getEventsCount(soClient, agentPolicyId),
- total: all.total,
+ total: allActive.total,
+ inactive: all.total - allActive.total,
online: online.total,
error: error.total,
offline: offline.total,
diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts
index 95072d3ae2e2c..b0dce60085529 100644
--- a/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts
+++ b/x-pack/plugins/fleet/server/services/fleet_server/elastic_index.ts
@@ -116,6 +116,11 @@ async function createIndex(esClient: ElasticsearchClient, indexName: string, ind
index: indexName,
body: {
...indexData,
+ settings: {
+ ...(indexData.settings || {}),
+ auto_expand_replicas: '0-1',
+ },
+
mappings: Object.assign({
...indexData.mappings,
_meta: { ...(indexData.mappings._meta || {}), migrationHash },
diff --git a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json
index 3008ee74ab50c..94ad02c6d5f18 100644
--- a/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json
+++ b/x-pack/plugins/fleet/server/services/fleet_server/elasticsearch/fleet_actions.json
@@ -24,6 +24,9 @@
},
"type": {
"type": "keyword"
+ },
+ "user_id" : {
+ "type": "keyword"
}
}
}
diff --git a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts
index f078b214e4dfd..7af2b791f3707 100644
--- a/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts
+++ b/x-pack/plugins/fleet/server/services/fleet_server/saved_object_migrations.ts
@@ -25,6 +25,7 @@ import { listEnrollmentApiKeys, getEnrollmentAPIKey } from '../api_keys/enrollme
import { appContextService } from '../app_context';
import { isAgentsSetup } from '../agents';
import { agentPolicyService } from '../agent_policy';
+import { invalidateAPIKeys } from '../api_keys';
export async function runFleetServerMigration() {
// If Agents are not setup skip as there is nothing to migrate
@@ -56,6 +57,7 @@ function getInternalUserSOClient() {
async function migrateAgents() {
const esClient = appContextService.getInternalUserESClient();
const soClient = getInternalUserSOClient();
+ const logger = appContextService.getLogger();
let hasMore = true;
while (hasMore) {
const res = await soClient.find({
@@ -75,11 +77,20 @@ async function migrateAgents() {
.getEncryptedSavedObjects()
.getDecryptedAsInternalUser(AGENT_SAVED_OBJECT_TYPE, so.id);
+ await invalidateAPIKeys(
+ soClient,
+ [attributes.access_api_key_id, attributes.default_api_key_id].filter(
+ (keyId): keyId is string => keyId !== undefined
+ )
+ ).catch((error) => {
+ logger.error(`Invalidating API keys for agent ${so.id} failed: ${error.message}`);
+ });
+
const body: FleetServerAgent = {
type: attributes.type,
- active: attributes.active,
+ active: false,
enrolled_at: attributes.enrolled_at,
- unenrolled_at: attributes.unenrolled_at,
+ unenrolled_at: new Date().toISOString(),
unenrollment_started_at: attributes.unenrollment_started_at,
upgraded_at: attributes.upgraded_at,
upgrade_started_at: attributes.upgrade_started_at,
diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx
index a210831eef865..f6d739078002e 100644
--- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx
+++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/job_setup_screen.tsx
@@ -24,6 +24,7 @@ import { FixedDatePicker } from '../../../../../../components/fixed_datepicker';
import { DEFAULT_K8S_PARTITION_FIELD } from '../../../../../../containers/ml/modules/metrics_k8s/module_descriptor';
import { MetricsExplorerKueryBar } from '../../../../metrics_explorer/components/kuery_bar';
import { convertKueryToElasticSearchQuery } from '../../../../../../utils/kuery';
+import { useUiTracker } from '../../../../../../../../observability/public';
interface Props {
jobType: 'hosts' | 'kubernetes';
@@ -40,6 +41,7 @@ export const JobSetupScreen = (props: Props) => {
const k = useMetricK8sModuleContext();
const [filter, setFilter] = useState('');
const [filterQuery, setFilterQuery] = useState('');
+ const trackMetric = useUiTracker({ app: 'infra_metrics' });
const { createDerivedIndexPattern } = useSourceViaHttp({
sourceId: 'default',
});
@@ -137,9 +139,25 @@ export const JobSetupScreen = (props: Props) => {
useEffect(() => {
if (setupStatus.type === 'succeeded') {
+ if (props.jobType === 'kubernetes') {
+ trackMetric({ metric: 'metrics_ml_anomaly_detection_k8s_enabled' });
+ if (
+ partitionField &&
+ (partitionField.length !== 1 || partitionField[0] !== DEFAULT_K8S_PARTITION_FIELD)
+ ) {
+ trackMetric({ metric: 'metrics_ml_anomaly_detection_k8s_partition_changed' });
+ }
+ } else {
+ trackMetric({ metric: 'metrics_ml_anomaly_detection_hosts_enabled' });
+ if (partitionField) {
+ trackMetric({ metric: 'metrics_ml_anomaly_detection_hosts_partition_changed' });
+ }
+ trackMetric({ metric: 'metrics_ml_anomaly_detection_hosts_enabled' });
+ }
+
goHome();
}
- }, [setupStatus, goHome]);
+ }, [setupStatus, props.jobType, partitionField, trackMetric, goHome]);
return (
<>
diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx
index 9d5feec9f21e6..dbc10c751a649 100644
--- a/x-pack/plugins/lens/public/app_plugin/app.tsx
+++ b/x-pack/plugins/lens/public/app_plugin/app.tsx
@@ -531,7 +531,13 @@ export function App({
const { TopNavMenu } = navigation.ui;
- const savingPermitted = Boolean(state.isSaveable && application.capabilities.visualize.save);
+ const savingToLibraryPermitted = Boolean(
+ state.isSaveable && application.capabilities.visualize.save
+ );
+ const savingToDashboardPermitted = Boolean(
+ state.isSaveable && application.capabilities.dashboard?.showWriteControls
+ );
+
const unsavedTitle = i18n.translate('xpack.lens.app.unsavedFilename', {
defaultMessage: 'unsaved',
});
@@ -545,8 +551,10 @@ export function App({
state.isSaveable && state.activeData && Object.keys(state.activeData).length
),
isByValueMode: getIsByValueMode(),
+ allowByValue: dashboardFeatureFlag.allowByValueEmbeddables,
showCancel: Boolean(state.isLinkedToOriginatingApp),
- savingPermitted,
+ savingToLibraryPermitted,
+ savingToDashboardPermitted,
actions: {
exportToCSV: () => {
if (!state.activeData) {
@@ -577,7 +585,7 @@ export function App({
}
},
saveAndReturn: () => {
- if (savingPermitted && lastKnownDoc) {
+ if (savingToDashboardPermitted && lastKnownDoc) {
// disabling the validation on app leave because the document has been saved.
onAppLeave((actions) => {
return actions.default();
@@ -597,7 +605,7 @@ export function App({
}
},
showSaveModal: () => {
- if (savingPermitted) {
+ if (savingToDashboardPermitted || savingToLibraryPermitted) {
setState((s) => ({ ...s, isSaveModalVisible: true }));
}
},
@@ -697,6 +705,7 @@ export function App({
{
const {
originatingApp,
+ savingToLibraryPermitted,
savedObjectsTagging,
tagsIds,
lastKnownDoc,
@@ -85,13 +87,15 @@ export const SaveModal = (props: Props) => {
{
const saveToLibrary = Boolean(saveProps.addToLibrary);
onSave(saveProps, { saveToLibrary });
}}
onClose={onClose}
documentInfo={{
- id: lastKnownDoc.savedObjectId,
+ // if the user cannot save to the library - treat this as a new document.
+ id: savingToLibraryPermitted ? lastKnownDoc.savedObjectId : undefined,
title: lastKnownDoc.title || '',
description: lastKnownDoc.description || '',
}}
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
index 157975b630e1e..00eaadeaf8299 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.test.tsx
@@ -112,7 +112,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -151,7 +154,7 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: { canSaveDashboards: true, canSaveVisualizations: true },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -191,7 +194,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -231,7 +237,10 @@ describe('embeddable', () => {
indexPatternService: ({
get: (id: string) => Promise.resolve({ id }),
} as unknown) as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -266,7 +275,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -307,7 +319,7 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: { canSaveDashboards: true, canSaveVisualizations: true },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -352,7 +364,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -395,7 +410,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -445,7 +463,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -495,7 +516,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -544,7 +568,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: ({ get: jest.fn() } as unknown) as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -582,7 +609,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -620,7 +650,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -658,7 +691,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -711,7 +747,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -780,7 +819,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -824,7 +866,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
@@ -868,7 +913,10 @@ describe('embeddable', () => {
expressionRenderer,
basePath,
indexPatternService: {} as IndexPatternsContract,
- editable: true,
+ capabilities: {
+ canSaveDashboards: true,
+ canSaveVisualizations: true,
+ },
getTrigger,
documentToExpression: () =>
Promise.resolve({
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
index 1db067606dc82..a3316e0083d35 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable.tsx
@@ -88,13 +88,13 @@ export interface LensEmbeddableDeps {
documentToExpression: (
doc: Document
) => Promise<{ ast: Ast | null; errors: ErrorMessage[] | undefined }>;
- editable: boolean;
indexPatternService: IndexPatternsContract;
expressionRenderer: ReactExpressionRendererType;
timefilter: TimefilterContract;
basePath: IBasePath;
getTrigger?: UiActionsStart['getTrigger'] | undefined;
getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions'];
+ capabilities: { canSaveVisualizations: boolean; canSaveDashboards: boolean };
}
export class Embeddable
@@ -129,7 +129,6 @@ export class Embeddable
initialInput,
{
editApp: 'lens',
- editable: deps.editable,
},
parent
);
@@ -326,7 +325,7 @@ export class Embeddable
hasCompatibleActions={this.hasCompatibleActions}
className={input.className}
style={input.style}
- canEdit={this.deps.editable && input.viewMode === 'edit'}
+ canEdit={this.getIsEditable() && input.viewMode === 'edit'}
/>,
domNode
);
@@ -451,6 +450,7 @@ export class Embeddable
this.updateOutput({
...this.getOutput(),
defaultTitle: this.savedVis.title,
+ editable: this.getIsEditable(),
title,
editPath: getEditPath(savedObjectId),
editUrl: this.deps.basePath.prepend(`/app/lens${getEditPath(savedObjectId)}`),
@@ -458,6 +458,13 @@ export class Embeddable
});
}
+ private getIsEditable() {
+ return (
+ this.deps.capabilities.canSaveVisualizations ||
+ (!this.inputIsRefType(this.getInput()) && this.deps.capabilities.canSaveDashboards)
+ );
+ }
+
public inputIsRefType = (
input: LensByValueInput | LensByReferenceInput
): input is LensByReferenceInput => {
diff --git a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts
index a676b7283671c..1a4962bd1fe8e 100644
--- a/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts
+++ b/x-pack/plugins/lens/public/editor_frame_service/embeddable/embeddable_factory.ts
@@ -53,7 +53,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
public isEditable = async () => {
const { capabilities } = await this.getStartServices();
- return capabilities.visualize.save as boolean;
+ return Boolean(capabilities.visualize.save || capabilities.dashboard?.showWriteControls);
};
canCreateNew() {
@@ -86,6 +86,7 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
coreHttp,
attributeService,
indexPatternService,
+ capabilities,
} = await this.getStartServices();
const { Embeddable } = await import('../../async_services');
@@ -96,11 +97,14 @@ export class EmbeddableFactory implements EmbeddableFactoryDefinition {
indexPatternService,
timefilter,
expressionRenderer,
- editable: await this.isEditable(),
basePath: coreHttp.basePath,
getTrigger: uiActions?.getTrigger,
getTriggerCompatibleActions: uiActions?.getTriggerCompatibleActions,
documentToExpression,
+ capabilities: {
+ canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls),
+ canSaveVisualizations: Boolean(capabilities.visualize.save),
+ },
},
input,
parent
diff --git a/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts b/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts
index 5f81a74ab03ce..a8bc5b9a821f0 100644
--- a/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts
+++ b/x-pack/plugins/maps/public/classes/tooltips/tooltip_property.ts
@@ -7,7 +7,7 @@
import _ from 'lodash';
import { Filter } from '../../../../../../src/plugins/data/public';
-import { TooltipFeature } from '../../../../../plugins/maps/common/descriptor_types';
+import type { TooltipFeature } from '../../../../../plugins/maps/common/descriptor_types';
export interface ITooltipProperty {
getPropertyKey(): string;
diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts
index b1944f8136709..a4ce76b702d13 100644
--- a/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts
+++ b/x-pack/plugins/maps/public/embeddable/map_embeddable_factory.ts
@@ -11,7 +11,6 @@ import {
EmbeddableFactoryDefinition,
IContainer,
} from '../../../../../src/plugins/embeddable/public';
-import '../index.scss';
import { MAP_SAVED_OBJECT_TYPE, APP_ICON } from '../../common/constants';
import { getMapEmbeddableDisplayName } from '../../common/i18n_getters';
import { MapByReferenceInput, MapEmbeddableInput, MapByValueInput } from './types';
diff --git a/x-pack/plugins/maps/public/index.ts b/x-pack/plugins/maps/public/index.ts
index 3e6cd8d14ad37..dc9cb2d594fe3 100644
--- a/x-pack/plugins/maps/public/index.ts
+++ b/x-pack/plugins/maps/public/index.ts
@@ -19,6 +19,8 @@ export const plugin: PluginInitializer = (
export { MAP_SAVED_OBJECT_TYPE } from '../common/constants';
-export { RenderTooltipContentParams } from './classes/tooltips/tooltip_property';
+export type { RenderTooltipContentParams } from './classes/tooltips/tooltip_property';
export { MapsStartApi } from './api';
+
+export type { MapEmbeddable, MapEmbeddableInput } from './embeddable';
diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts
index 6fd14d8d42e18..e4b9397fab8e7 100644
--- a/x-pack/plugins/maps/public/kibana_services.ts
+++ b/x-pack/plugins/maps/public/kibana_services.ts
@@ -5,13 +5,12 @@
* 2.0.
*/
-import _ from 'lodash';
-import { CoreStart } from 'kibana/public';
+import type { CoreStart } from 'kibana/public';
import type { MapsEmsConfig } from '../../../../src/plugins/maps_ems/public';
-import { MapsConfigType } from '../config';
-import { MapsPluginStartDependencies } from './plugin';
-import { EMSSettings } from '../common/ems_settings';
-import { PaletteRegistry } from '../../../../src/plugins/charts/public';
+import type { MapsConfigType } from '../config';
+import type { MapsPluginStartDependencies } from './plugin';
+import type { EMSSettings } from '../common/ems_settings';
+import type { PaletteRegistry } from '../../../../src/plugins/charts/public';
let kibanaVersion: string;
export const setKibanaVersion = (version: string) => (kibanaVersion = version);
@@ -75,8 +74,22 @@ export const getEMSSettings = () => {
export const getEmsTileLayerId = () => getKibanaCommonConfig().emsTileLayerId;
-export const getRegionmapLayers = () => _.get(getKibanaCommonConfig(), 'regionmap.layers', []);
-export const getTilemap = () => _.get(getKibanaCommonConfig(), 'tilemap', []);
+export const getRegionmapLayers = () => {
+ const config = getKibanaCommonConfig();
+ if (config.regionmap && config.regionmap.layers) {
+ return config.regionmap.layers;
+ } else {
+ return [];
+ }
+};
+export const getTilemap = () => {
+ const config = getKibanaCommonConfig();
+ if (config.tilemap) {
+ return config.tilemap;
+ } else {
+ return {};
+ }
+};
export const getShareService = () => pluginsStart.share;
diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts
index 0d908356b714d..85b58da0ab09a 100644
--- a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts
+++ b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import '../../index.scss';
export * from '../../embeddable/map_embeddable';
export * from '../../kibana_services';
export { renderApp } from '../../render_app';
diff --git a/x-pack/plugins/maps/public/maps_vis_type_alias.ts b/x-pack/plugins/maps/public/maps_vis_type_alias.ts
index a3a8b55745d84..194b4595c0c93 100644
--- a/x-pack/plugins/maps/public/maps_vis_type_alias.ts
+++ b/x-pack/plugins/maps/public/maps_vis_type_alias.ts
@@ -6,12 +6,12 @@
*/
import { i18n } from '@kbn/i18n';
-import {
+import type {
VisualizationsSetup,
VisualizationStage,
} from '../../../../src/plugins/visualizations/public';
-import { SavedObject } from '../../../../src/core/types/saved_objects';
-import { MapSavedObject } from '../common/map_saved_object_type';
+import type { SavedObject } from '../../../../src/core/types/saved_objects';
+import type { MapSavedObject } from '../common/map_saved_object_type';
import {
APP_ID,
APP_ICON,
diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts
index be2e097c71dc5..7ddab6bf509ff 100644
--- a/x-pack/plugins/maps/public/plugin.ts
+++ b/x-pack/plugins/maps/public/plugin.ts
@@ -5,19 +5,19 @@
* 2.0.
*/
-import { Setup as InspectorSetupContract } from 'src/plugins/inspector/public';
-import { UiActionsStart } from 'src/plugins/ui_actions/public';
-import { NavigationPublicPluginStart } from 'src/plugins/navigation/public';
-import { Start as InspectorStartContract } from 'src/plugins/inspector/public';
-import { DashboardStart } from 'src/plugins/dashboard/public';
-import {
+import type { Setup as InspectorSetupContract } from 'src/plugins/inspector/public';
+import type { UiActionsStart } from 'src/plugins/ui_actions/public';
+import type { NavigationPublicPluginStart } from 'src/plugins/navigation/public';
+import type { Start as InspectorStartContract } from 'src/plugins/inspector/public';
+import type { DashboardStart } from 'src/plugins/dashboard/public';
+import type {
AppMountParameters,
CoreSetup,
CoreStart,
Plugin,
PluginInitializerContext,
- DEFAULT_APP_CATEGORIES,
} from '../../../../src/core/public';
+import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public';
// @ts-ignore
import { MapView } from './inspector/views/map_view';
import {
@@ -29,8 +29,8 @@ import {
} from './kibana_services';
import { featureCatalogueEntry } from './feature_catalogue_entry';
import { getMapsVisTypeAlias } from './maps_vis_type_alias';
-import { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
-import {
+import type { HomePublicPluginSetup } from '../../../../src/plugins/home/public';
+import type {
VisualizationsSetup,
VisualizationsStart,
} from '../../../../src/plugins/visualizations/public';
@@ -43,28 +43,27 @@ import {
} from './url_generator';
import { visualizeGeoFieldAction } from './trigger_actions/visualize_geo_field_action';
import { MapEmbeddableFactory } from './embeddable/map_embeddable_factory';
-import { EmbeddableSetup } from '../../../../src/plugins/embeddable/public';
+import type { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public';
import { MapsXPackConfig, MapsConfigType } from '../config';
import { getAppTitle } from '../common/i18n_getters';
import { lazyLoadMapModules } from './lazy_load_bundle';
import { MapsStartApi } from './api';
import { createLayerDescriptors, registerLayerWizard, registerSource } from './api';
-import { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public';
-import { EmbeddableStart } from '../../../../src/plugins/embeddable/public';
+import type { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public';
import type { MapsEmsPluginSetup } from '../../../../src/plugins/maps_ems/public';
-import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
-import { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/public';
-import { FileUploadPluginStart } from '../../file_upload/public';
-import { SavedObjectsStart } from '../../../../src/plugins/saved_objects/public';
-import { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public';
+import type { DataPublicPluginStart } from '../../../../src/plugins/data/public';
+import type { LicensingPluginSetup, LicensingPluginStart } from '../../licensing/public';
+import type { FileUploadPluginStart } from '../../file_upload/public';
+import type { SavedObjectsStart } from '../../../../src/plugins/saved_objects/public';
+import type { PresentationUtilPluginStart } from '../../../../src/plugins/presentation_util/public';
import {
getIsEnterprisePlus,
registerLicensedFeatures,
setLicensingPluginStart,
} from './licensed_features';
import { EMSSettings } from '../common/ems_settings';
-import { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public';
-import { ChartsPluginStart } from '../../../../src/plugins/charts/public';
+import type { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public';
+import type { ChartsPluginStart } from '../../../../src/plugins/charts/public';
export interface MapsPluginSetupDependencies {
inspector: InspectorSetupContract;
diff --git a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx
index 597cd8e9c4287..7e0aa59756876 100644
--- a/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx
+++ b/x-pack/plugins/maps/public/routes/map_page/top_nav_config.tsx
@@ -201,7 +201,11 @@ export function getTopNavConfig({
options={tagSelector}
/>
) : (
-
+
);
showSaveModal(saveModal, getCoreI18n().Context, PresentationUtilContext);
diff --git a/x-pack/plugins/maps/public/url_generator.ts b/x-pack/plugins/maps/public/url_generator.ts
index c82af369fe113..9f28b388c4756 100644
--- a/x-pack/plugins/maps/public/url_generator.ts
+++ b/x-pack/plugins/maps/public/url_generator.ts
@@ -6,17 +6,17 @@
*/
import rison from 'rison-node';
-import {
+import type {
TimeRange,
Filter,
Query,
- esFilters,
QueryState,
RefreshInterval,
} from '../../../../src/plugins/data/public';
+import { esFilters } from '../../../../src/plugins/data/public';
import { setStateToKbnUrl } from '../../../../src/plugins/kibana_utils/public';
-import { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public';
-import { LayerDescriptor } from '../common/descriptor_types';
+import type { UrlGeneratorsDefinition } from '../../../../src/plugins/share/public';
+import type { LayerDescriptor } from '../common/descriptor_types';
import { INITIAL_LAYERS_KEY } from '../common/constants';
import { lazyLoadMapModules } from './lazy_load_bundle';
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
index e1e78f8e310e1..129d592edd264 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/indicator_match_rule.spec.ts
@@ -502,7 +502,7 @@ describe('indicator match', () => {
{
line: 3,
text:
- ' "indicator": "{\\"first_seen\\":\\"2021-03-10T08:02:14.000Z\\",\\"file\\":{\\"size\\":80280,\\"pe\\":{},\\"type\\":\\"elf\\",\\"hash\\":{\\"sha256\\":\\"a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3\\",\\"tlsh\\":\\"6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE\\",\\"ssdeep\\":\\"1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL\\",\\"md5\\":\\"9b6c3518a91d23ed77504b5416bfb5b3\\"}},\\"type\\":\\"file\\",\\"matched\\":{\\"atomic\\":\\"a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3\\",\\"field\\":\\"myhash.mysha256\\",\\"id\\":\\"84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f\\",\\"index\\":\\"filebeat-7.12.0-2021.03.10-000001\\",\\"type\\":\\"file\\"}}"',
+ ' "indicator": "{\\"first_seen\\":\\"2021-03-10T08:02:14.000Z\\",\\"file\\":{\\"size\\":80280,\\"pe\\":{},\\"type\\":\\"elf\\",\\"hash\\":{\\"sha256\\":\\"a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3\\",\\"tlsh\\":\\"6D7312E017B517CC1371A8353BED205E9128223972AE35302E97528DF957703BAB2DBE\\",\\"ssdeep\\":\\"1536:87vbq1lGAXSEYQjbChaAU2yU23M51DjZgSQAvcYkFtZTjzBht5:8D+CAXFYQChaAUk5ljnQssL\\",\\"md5\\":\\"9b6c3518a91d23ed77504b5416bfb5b3\\"}},\\"type\\":\\"file\\",\\"event\\":{\\"reference\\":\\"https://urlhaus-api.abuse.ch/v1/download/a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3/\\",\\"ingested\\":\\"2021-03-10T14:51:09.809069Z\\",\\"created\\":\\"2021-03-10T14:51:07.663Z\\",\\"kind\\":\\"enrichment\\",\\"module\\":\\"threatintel\\",\\"category\\":\\"threat\\",\\"type\\":\\"indicator\\",\\"dataset\\":\\"threatintel.abusemalware\\"},\\"matched\\":{\\"atomic\\":\\"a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3\\",\\"field\\":\\"myhash.mysha256\\",\\"id\\":\\"84cf452c1e0375c3d4412cb550bd1783358468a3b3b777da4829d72c7d6fb74f\\",\\"index\\":\\"filebeat-7.12.0-2021.03.10-000001\\",\\"type\\":\\"file\\"}}"',
},
{ line: 2, text: ' }' },
];
diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx
index eceea1de4edc0..297746fd23632 100644
--- a/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx
+++ b/x-pack/plugins/security_solution/public/network/components/embeddables/embedded_map_helpers.tsx
@@ -12,15 +12,11 @@ import minimatch from 'minimatch';
import { IndexPatternMapping } from './types';
import { getLayerList } from './map_config';
import { MAP_SAVED_OBJECT_TYPE } from '../../../../../maps/public';
-import {
+import type {
+ RenderTooltipContentParams,
MapEmbeddable,
MapEmbeddableInput,
- // eslint-disable-next-line @kbn/eslint/no-restricted-paths
-} from '../../../../../../plugins/maps/public/embeddable';
-import {
- RenderTooltipContentParams,
- // eslint-disable-next-line @kbn/eslint/no-restricted-paths
-} from '../../../../../../plugins/maps/public/classes/tooltips/tooltip_property';
+} from '../../../../../../plugins/maps/public';
import * as i18n from './translations';
import { Query, Filter } from '../../../../../../../src/plugins/data/public';
import {
diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts b/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts
index 7d9c66261924b..6317cad7f8d98 100644
--- a/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts
+++ b/x-pack/plugins/security_solution/public/network/components/embeddables/types.ts
@@ -5,8 +5,7 @@
* 2.0.
*/
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { RenderTooltipContentParams } from '../../../../../maps/public/classes/tooltips/tooltip_property';
+import type { RenderTooltipContentParams } from '../../../../../maps/public';
export interface IndexPatternMapping {
title: string;
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts
index c6f432a28aee4..326d5777543be 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_signals_template.ts
@@ -21,7 +21,7 @@ import ecsMapping from './ecs_mapping.json';
incremented by 10 in order to add "room" for the aforementioned patch
release
*/
-export const SIGNALS_TEMPLATE_VERSION = 25;
+export const SIGNALS_TEMPLATE_VERSION = 26;
export const MIN_EQL_RULE_INDEX_VERSION = 2;
export const getSignalsTemplate = (index: string) => {
@@ -45,6 +45,19 @@ export const getSignalsTemplate = (index: string) => {
properties: {
...ecsMapping.mappings.properties,
signal: signalsMapping.mappings.properties.signal,
+ threat: {
+ ...ecsMapping.mappings.properties.threat,
+ properties: {
+ ...ecsMapping.mappings.properties.threat.properties,
+ indicator: {
+ ...ecsMapping.mappings.properties.threat.properties.indicator,
+ properties: {
+ ...ecsMapping.mappings.properties.threat.properties.indicator.properties,
+ event: ecsMapping.mappings.properties.event,
+ },
+ },
+ },
+ },
},
_meta: {
version: SIGNALS_TEMPLATE_VERSION,
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts
index 7b3ca099cc93c..7c80572f6b1ee 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.test.ts
@@ -83,6 +83,7 @@ describe('buildMatchedIndicator', () => {
getThreatListItemMock({
_id: '123',
_source: {
+ event: { dataset: 'abuse.ch', reference: 'https://test.com' },
threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } },
},
}),
@@ -117,6 +118,16 @@ describe('buildMatchedIndicator', () => {
expect(get(indicator, 'matched.atomic')).toEqual('domain_1');
});
+ it('returns event values as a part of threat', () => {
+ const [indicator] = buildMatchedIndicator({
+ queries,
+ threats,
+ indicatorPath,
+ });
+ const expectedEvent = threats[0]._source!.event;
+ expect(get(indicator, 'event')).toEqual(expectedEvent);
+ });
+
it('returns the _id of the matched indicator as matched.id', () => {
const [indicator] = buildMatchedIndicator({
queries,
@@ -162,12 +173,16 @@ describe('buildMatchedIndicator', () => {
getThreatListItemMock({
_id: '123',
_source: {
- threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } },
+ event: { reference: 'https://test.com' },
+ threat: {
+ indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' },
+ },
},
}),
getThreatListItemMock({
_id: '456',
_source: {
+ event: { reference: 'https://test2.com' },
threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } },
},
}),
@@ -205,6 +220,10 @@ describe('buildMatchedIndicator', () => {
},
other: 'other_1',
type: 'type_1',
+ event: {
+ reference: 'https://test.com',
+ dataset: 'abuse.ch',
+ },
},
]);
});
@@ -214,6 +233,9 @@ describe('buildMatchedIndicator', () => {
getThreatListItemMock({
_id: '123',
_source: {
+ event: {
+ reference: 'https://test3.com',
+ },
'threat.indicator.domain': 'domain_1',
custom: {
indicator: {
@@ -244,6 +266,9 @@ describe('buildMatchedIndicator', () => {
type: 'indicator_type',
},
type: 'indicator_type',
+ event: {
+ reference: 'https://test3.com',
+ },
},
]);
});
@@ -307,6 +332,9 @@ describe('buildMatchedIndicator', () => {
getThreatListItemMock({
_id: '123',
_source: {
+ event: {
+ reference: 'https://test4.com',
+ },
threat: {
indicator: [
{ domain: 'foo', type: 'first' },
@@ -334,6 +362,9 @@ describe('buildMatchedIndicator', () => {
type: 'first',
},
type: 'first',
+ event: {
+ reference: 'https://test4.com',
+ },
},
]);
});
@@ -392,6 +423,9 @@ describe('enrichSignalThreatMatches', () => {
getThreatListItemMock({
_id: '123',
_source: {
+ event: {
+ category: 'malware',
+ },
threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } },
},
}),
@@ -419,7 +453,11 @@ describe('enrichSignalThreatMatches', () => {
it('preserves existing threat.indicator objects on signals', async () => {
const signalHit = getSignalHitMock({
- _source: { '@timestamp': 'mocked', threat: { indicator: [{ existing: 'indicator' }] } },
+ _source: {
+ '@timestamp': 'mocked',
+ event: { category: 'malware' },
+ threat: { indicator: [{ existing: 'indicator' }] },
+ },
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
@@ -444,6 +482,9 @@ describe('enrichSignalThreatMatches', () => {
},
other: 'other_1',
type: 'type_1',
+ event: {
+ category: 'malware',
+ },
},
]);
});
@@ -477,7 +518,11 @@ describe('enrichSignalThreatMatches', () => {
it('preserves an existing threat.indicator object on signals', async () => {
const signalHit = getSignalHitMock({
- _source: { '@timestamp': 'mocked', threat: { indicator: { existing: 'indicator' } } },
+ _source: {
+ '@timestamp': 'mocked',
+ event: { category: 'virus' },
+ threat: { indicator: { existing: 'indicator' } },
+ },
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
@@ -502,6 +547,9 @@ describe('enrichSignalThreatMatches', () => {
},
other: 'other_1',
type: 'type_1',
+ event: {
+ category: 'malware',
+ },
},
]);
});
@@ -573,12 +621,14 @@ describe('enrichSignalThreatMatches', () => {
getThreatListItemMock({
_id: '123',
_source: {
+ event: { category: 'threat' },
threat: { indicator: { domain: 'domain_1', other: 'other_1', type: 'type_1' } },
},
}),
getThreatListItemMock({
_id: '456',
_source: {
+ event: { category: 'bad' },
threat: { indicator: { domain: 'domain_2', other: 'other_2', type: 'type_2' } },
},
}),
@@ -622,6 +672,9 @@ describe('enrichSignalThreatMatches', () => {
field: 'event.field',
type: 'type_1',
},
+ event: {
+ category: 'threat',
+ },
other: 'other_1',
type: 'type_1',
},
@@ -634,6 +687,9 @@ describe('enrichSignalThreatMatches', () => {
field: 'event.other',
type: 'type_2',
},
+ event: {
+ category: 'bad',
+ },
other: 'other_2',
type: 'type_2',
},
diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts
index 83a3ce8cb773f..c26f03d1dd480 100644
--- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts
+++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/enrich_signal_threat_matches.ts
@@ -57,9 +57,11 @@ export const buildMatchedIndicator = ({
}
const atomic = get(matchedThreat?._source, query.value) as unknown;
const type = get(indicator, 'type') as unknown;
+ const event = get(matchedThreat?._source, 'event') as unknown;
return {
...indicator,
+ event,
matched: { atomic, field: query.field, id: query.id, index: query.index, type },
};
});
diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts
index 335b18de92850..45b8b23cae477 100644
--- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts
+++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts
@@ -108,6 +108,14 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
]);
};
+ const setRestoreSnapshotResponse = (response?: HttpResponse) => {
+ server.respondWith('POST', `${API_BASE_PATH}restore/:repository/:snapshot`, [
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify(response),
+ ]);
+ };
+
return {
setLoadRepositoriesResponse,
setLoadRepositoryTypesResponse,
@@ -119,6 +127,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
setAddPolicyResponse,
setGetPolicyResponse,
setCleanupRepositoryResponse,
+ setRestoreSnapshotResponse,
};
};
diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts
index c0ffae81a4258..5bc970a1143a4 100644
--- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts
+++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts
@@ -25,6 +25,7 @@ const initTestBed = registerTestBed(
const setupActions = (testBed: TestBed) => {
const { find, component, form } = testBed;
+
return {
findDataStreamCallout() {
return find('dataStreamWarningCallOut');
@@ -37,6 +38,28 @@ const setupActions = (testBed: TestBed) => {
component.update();
},
+
+ toggleIncludeAliases() {
+ act(() => {
+ form.toggleEuiSwitch('includeAliasesSwitch');
+ });
+
+ component.update();
+ },
+
+ goToStep(step: number) {
+ while (--step > 0) {
+ find('nextButton').simulate('click');
+ }
+ component.update();
+ },
+
+ async clickRestore() {
+ await act(async () => {
+ find('restoreButton').simulate('click');
+ });
+ component.update();
+ },
};
};
@@ -58,5 +81,8 @@ export const setup = async (): Promise => {
export type RestoreSnapshotFormTestSubject =
| 'snapshotRestoreStepLogistics'
| 'includeGlobalStateSwitch'
+ | 'includeAliasesSwitch'
+ | 'nextButton'
+ | 'restoreButton'
| 'systemIndicesInfoCallOut'
| 'dataStreamWarningCallOut';
diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts
index 2fecce36f09df..9f12415b70a9f 100644
--- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts
+++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts
@@ -33,7 +33,7 @@ describe('', () => {
testBed.component.update();
});
- it('shows the data streams warning when the snapshot has data streams', () => {
+ test('shows the data streams warning when the snapshot has data streams', () => {
const { exists } = testBed;
expect(exists('dataStreamWarningCallOut')).toBe(true);
});
@@ -49,7 +49,7 @@ describe('', () => {
testBed.component.update();
});
- it('hides the data streams warning when the snapshot has data streams', () => {
+ test('hides the data streams warning when the snapshot has data streams', () => {
const { exists } = testBed;
expect(exists('dataStreamWarningCallOut')).toBe(false);
});
@@ -65,7 +65,7 @@ describe('', () => {
testBed.component.update();
});
- it('shows an info callout when include_global_state is enabled', () => {
+ test('shows an info callout when include_global_state is enabled', () => {
const { exists, actions } = testBed;
expect(exists('systemIndicesInfoCallOut')).toBe(false);
@@ -75,4 +75,30 @@ describe('', () => {
expect(exists('systemIndicesInfoCallOut')).toBe(true);
});
});
+
+ // NOTE: This suite can be expanded to simulate the user setting non-default values for all of
+ // the form controls and asserting that the correct payload is sent to the API.
+ describe('include aliases', () => {
+ beforeEach(async () => {
+ httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot());
+ httpRequestsMockHelpers.setRestoreSnapshotResponse({});
+
+ await act(async () => {
+ testBed = await setup();
+ });
+
+ testBed.component.update();
+ });
+
+ test('is sent to the API', async () => {
+ const { actions } = testBed;
+ actions.toggleIncludeAliases();
+ actions.goToStep(3);
+ await actions.clickRestore();
+
+ const expectedPayload = { includeAliases: false };
+ const latestRequest = server.requests[server.requests.length - 1];
+ expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expectedPayload);
+ });
+ });
});
diff --git a/x-pack/plugins/snapshot_restore/common/lib/index.ts b/x-pack/plugins/snapshot_restore/common/lib/index.ts
index a375709cee7c5..fc8015c5b807b 100644
--- a/x-pack/plugins/snapshot_restore/common/lib/index.ts
+++ b/x-pack/plugins/snapshot_restore/common/lib/index.ts
@@ -6,10 +6,7 @@
*/
export { flatten } from './flatten';
-export {
- deserializeRestoreSettings,
- serializeRestoreSettings,
-} from './restore_settings_serialization';
+export { serializeRestoreSettings } from './restore_settings_serialization';
export {
deserializeSnapshotDetails,
deserializeSnapshotConfig,
diff --git a/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.test.ts b/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.test.ts
index bb640000cc89a..3a78001c742ff 100644
--- a/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.test.ts
+++ b/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.test.ts
@@ -5,10 +5,7 @@
* 2.0.
*/
-import {
- deserializeRestoreSettings,
- serializeRestoreSettings,
-} from './restore_settings_serialization';
+import { serializeRestoreSettings } from './restore_settings_serialization';
describe('restore_settings_serialization()', () => {
it('should serialize blank restore settings', () => {
@@ -56,6 +53,7 @@ describe('restore_settings_serialization()', () => {
indexSettings: '{"modified_setting":123}',
ignoreIndexSettings: ['setting1'],
ignoreUnavailable: true,
+ includeAliases: true,
})
).toEqual({
indices: ['foo', 'bar'],
@@ -66,6 +64,7 @@ describe('restore_settings_serialization()', () => {
index_settings: { modified_setting: 123 },
ignore_index_settings: ['setting1'],
ignore_unavailable: true,
+ include_aliases: true,
});
});
@@ -76,47 +75,4 @@ describe('restore_settings_serialization()', () => {
})
).toEqual({});
});
-
- it('should deserialize blank restore settings', () => {
- expect(deserializeRestoreSettings({})).toEqual({});
- });
-
- it('should deserialize partial restore settings', () => {
- expect(deserializeRestoreSettings({})).toEqual({});
- expect(
- deserializeRestoreSettings({
- indices: ['foo', 'bar'],
- ignore_index_settings: ['setting1'],
- partial: true,
- })
- ).toEqual({
- indices: ['foo', 'bar'],
- ignoreIndexSettings: ['setting1'],
- partial: true,
- });
- });
-
- it('should deserialize full restore settings', () => {
- expect(
- deserializeRestoreSettings({
- indices: ['foo', 'bar'],
- rename_pattern: 'capture_pattern',
- rename_replacement: 'replacement_pattern',
- include_global_state: true,
- partial: true,
- index_settings: { modified_setting: 123 },
- ignore_index_settings: ['setting1'],
- ignore_unavailable: true,
- })
- ).toEqual({
- indices: ['foo', 'bar'],
- renamePattern: 'capture_pattern',
- renameReplacement: 'replacement_pattern',
- includeGlobalState: true,
- partial: true,
- indexSettings: '{"modified_setting":123}',
- ignoreIndexSettings: ['setting1'],
- ignoreUnavailable: true,
- });
- });
});
diff --git a/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.ts b/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.ts
index 5e026246c77b9..c017bc721884c 100644
--- a/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.ts
+++ b/x-pack/plugins/snapshot_restore/common/lib/restore_settings_serialization.ts
@@ -26,6 +26,7 @@ export function serializeRestoreSettings(restoreSettings: RestoreSettings): Rest
indexSettings,
ignoreIndexSettings,
ignoreUnavailable,
+ includeAliases,
} = restoreSettings;
let parsedIndexSettings: RestoreSettingsEs['index_settings'] | undefined;
@@ -47,32 +48,7 @@ export function serializeRestoreSettings(restoreSettings: RestoreSettings): Rest
index_settings: parsedIndexSettings,
ignore_index_settings: ignoreIndexSettings,
ignore_unavailable: ignoreUnavailable,
- };
-
- return removeUndefinedSettings(settings);
-}
-
-export function deserializeRestoreSettings(restoreSettingsEs: RestoreSettingsEs): RestoreSettings {
- const {
- indices,
- rename_pattern: renamePattern,
- rename_replacement: renameReplacement,
- include_global_state: includeGlobalState,
- partial,
- index_settings: indexSettings,
- ignore_index_settings: ignoreIndexSettings,
- ignore_unavailable: ignoreUnavailable,
- } = restoreSettingsEs;
-
- const settings: RestoreSettings = {
- indices,
- renamePattern,
- renameReplacement,
- includeGlobalState,
- partial,
- indexSettings: indexSettings ? JSON.stringify(indexSettings) : undefined,
- ignoreIndexSettings,
- ignoreUnavailable,
+ include_aliases: includeAliases,
};
return removeUndefinedSettings(settings);
diff --git a/x-pack/plugins/snapshot_restore/common/types/restore.ts b/x-pack/plugins/snapshot_restore/common/types/restore.ts
index 1bbd5cdd5a56c..9e9b91de1859e 100644
--- a/x-pack/plugins/snapshot_restore/common/types/restore.ts
+++ b/x-pack/plugins/snapshot_restore/common/types/restore.ts
@@ -14,6 +14,7 @@ export interface RestoreSettings {
indexSettings?: string;
ignoreIndexSettings?: string[];
ignoreUnavailable?: boolean;
+ includeAliases?: boolean;
}
export interface RestoreSettingsEs {
@@ -25,6 +26,7 @@ export interface RestoreSettingsEs {
index_settings?: { [key: string]: any };
ignore_index_settings?: string[];
ignore_unavailable?: boolean;
+ include_aliases?: boolean;
}
export interface SnapshotRestore {
diff --git a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/restore_snapshot_form.tsx b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/restore_snapshot_form.tsx
index f672300db8821..82ace79f49f5d 100644
--- a/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/restore_snapshot_form.tsx
+++ b/x-pack/plugins/snapshot_restore/public/application/components/restore_snapshot_form/restore_snapshot_form.tsx
@@ -140,6 +140,7 @@ export const RestoreSnapshotForm: React.FunctionComponent = ({
iconType="arrowRight"
onClick={() => onNext()}
disabled={!validation.isValid}
+ data-test-subj="nextButton"
>
= ({
iconType="check"
onClick={() => executeRestore()}
isLoading={isSaving}
+ data-test-subj="restoreButton"
>
{isSaving ? (
=
renameReplacement,
partial,
includeGlobalState,
+ includeAliases,
} = restoreSettings;
// States for choosing all indices, or a subset, including caching previously chosen subset list
@@ -625,6 +626,41 @@ export const RestoreSnapshotStepLogistics: React.FunctionComponent =
/>
+
+ {/* Include aliases */}
+
+
+
+
+
+ }
+ description={
+
+ }
+ fullWidth
+ >
+
+
+ }
+ checked={includeAliases === undefined ? true : includeAliases}
+ onChange={(e) => updateRestoreSettings({ includeAliases: e.target.checked })}
+ data-test-subj="includeAliasesSwitch"
+ />
+
+
);
};
diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/validate_schemas.ts b/x-pack/plugins/snapshot_restore/server/routes/api/validate_schemas.ts
index fe156f6ba9750..af31466c2cefe 100644
--- a/x-pack/plugins/snapshot_restore/server/routes/api/validate_schemas.ts
+++ b/x-pack/plugins/snapshot_restore/server/routes/api/validate_schemas.ts
@@ -176,4 +176,5 @@ export const restoreSettingsSchema = schema.object({
indexSettings: schema.maybe(schema.string()),
ignoreIndexSettings: schema.maybe(schema.arrayOf(schema.string())),
ignoreUnavailable: schema.maybe(schema.boolean()),
+ includeAliases: schema.maybe(schema.boolean()),
});
diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json
index ef09937da3fbc..e1e0711c2bb2c 100644
--- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json
+++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json
@@ -1837,17 +1837,35 @@
},
"agents": {
"properties": {
- "total": {
- "type": "long"
+ "total_enrolled": {
+ "type": "long",
+ "_meta": {
+ "description": "The total number of enrolled agents, in any state"
+ }
},
- "online": {
- "type": "long"
+ "healthy": {
+ "type": "long",
+ "_meta": {
+ "description": "The total number of enrolled agents in a healthy state"
+ }
},
- "error": {
- "type": "long"
+ "unhealthy": {
+ "type": "long",
+ "_meta": {
+ "description": "The total number of enrolled agents in an unhealthy state"
+ }
},
"offline": {
- "type": "long"
+ "type": "long",
+ "_meta": {
+ "description": "The total number of enrolled agents currently offline"
+ }
+ },
+ "total_all_statuses": {
+ "type": "long",
+ "_meta": {
+ "description": "The total number of agents in any state, both enrolled and inactive"
+ }
}
}
},
@@ -1978,6 +1996,42 @@
"xy_layer_added": {
"type": "long"
},
+ "open_field_editor_edit": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the editor flyout to edit a field from within Lens."
+ }
+ },
+ "open_field_editor_add": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the editor flyout to add a field from within Lens."
+ }
+ },
+ "save_field_edit": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user edited a field from within Lens."
+ }
+ },
+ "save_field_add": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user added a field from within Lens."
+ }
+ },
+ "open_field_delete_modal": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the field delete modal from within Lens."
+ }
+ },
+ "delete_field": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user deleted a field from within Lens."
+ }
+ },
"indexpattern_dimension_operation_terms": {
"type": "long",
"_meta": {
@@ -2034,70 +2088,50 @@
},
"indexpattern_dimension_operation_range": {
"type": "long",
- "_meta": { "description": "Number of times the range function was selected" }
+ "_meta": {
+ "description": "Number of times the range function was selected"
+ }
},
"indexpattern_dimension_operation_median": {
"type": "long",
- "_meta": { "description": "Number of times the median function was selected" }
+ "_meta": {
+ "description": "Number of times the median function was selected"
+ }
},
"indexpattern_dimension_operation_percentile": {
- "type": "long",
- "_meta": { "description": "Number of times the percentile function was selected" }
- },
- "indexpattern_dimension_operation_last_value": {
- "type": "long",
- "_meta": { "description": "Number of times the last value function was selected" }
- },
- "indexpattern_dimension_operation_cumulative_sum": {
- "type": "long",
- "_meta": { "description": "Number of times the cumulative sum function was selected" }
- },
- "indexpattern_dimension_operation_counter_rate": {
- "type": "long",
- "_meta": { "description": "Number of times the counter rate function was selected" }
- },
- "indexpattern_dimension_operation_derivative": {
- "type": "long",
- "_meta": { "description": "Number of times the derivative function was selected" }
- },
- "indexpattern_dimension_operation_moving_average": {
- "type": "long",
- "_meta": { "description": "Number of times the moving average function was selected" }
- },
- "open_field_editor_edit": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the editor flyout to edit a field from within Lens."
+ "description": "Number of times the percentile function was selected"
}
},
- "open_field_editor_add": {
+ "indexpattern_dimension_operation_last_value": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the editor flyout to add a field from within Lens."
+ "description": "Number of times the last value function was selected"
}
},
- "save_field_edit": {
+ "indexpattern_dimension_operation_cumulative_sum": {
"type": "long",
"_meta": {
- "description": "Number of times the user edited a field from within Lens."
+ "description": "Number of times the cumulative sum function was selected"
}
},
- "save_field_add": {
+ "indexpattern_dimension_operation_counter_rate": {
"type": "long",
"_meta": {
- "description": "Number of times the user added a field from within Lens."
+ "description": "Number of times the counter rate function was selected"
}
},
- "open_field_delete_modal": {
+ "indexpattern_dimension_operation_derivative": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the field delete modal from within Lens."
+ "description": "Number of times the derivative function was selected"
}
},
- "delete_field": {
+ "indexpattern_dimension_operation_moving_average": {
"type": "long",
"_meta": {
- "description": "Number of times the user deleted a field from within Lens."
+ "description": "Number of times the moving average function was selected"
}
}
}
@@ -2185,6 +2219,42 @@
"xy_layer_added": {
"type": "long"
},
+ "open_field_editor_edit": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the editor flyout to edit a field from within Lens."
+ }
+ },
+ "open_field_editor_add": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the editor flyout to add a field from within Lens."
+ }
+ },
+ "save_field_edit": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user edited a field from within Lens."
+ }
+ },
+ "save_field_add": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user added a field from within Lens."
+ }
+ },
+ "open_field_delete_modal": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user opened the field delete modal from within Lens."
+ }
+ },
+ "delete_field": {
+ "type": "long",
+ "_meta": {
+ "description": "Number of times the user deleted a field from within Lens."
+ }
+ },
"indexpattern_dimension_operation_terms": {
"type": "long",
"_meta": {
@@ -2241,70 +2311,50 @@
},
"indexpattern_dimension_operation_range": {
"type": "long",
- "_meta": { "description": "Number of times the range function was selected" }
+ "_meta": {
+ "description": "Number of times the range function was selected"
+ }
},
"indexpattern_dimension_operation_median": {
"type": "long",
- "_meta": { "description": "Number of times the median function was selected" }
+ "_meta": {
+ "description": "Number of times the median function was selected"
+ }
},
"indexpattern_dimension_operation_percentile": {
- "type": "long",
- "_meta": { "description": "Number of times the percentile function was selected" }
- },
- "indexpattern_dimension_operation_last_value": {
- "type": "long",
- "_meta": { "description": "Number of times the last value function was selected" }
- },
- "indexpattern_dimension_operation_cumulative_sum": {
- "type": "long",
- "_meta": { "description": "Number of times the cumulative sum function was selected" }
- },
- "indexpattern_dimension_operation_counter_rate": {
- "type": "long",
- "_meta": { "description": "Number of times the counter rate function was selected" }
- },
- "indexpattern_dimension_operation_derivative": {
- "type": "long",
- "_meta": { "description": "Number of times the derivative function was selected" }
- },
- "indexpattern_dimension_operation_moving_average": {
- "type": "long",
- "_meta": { "description": "Number of times the moving average function was selected" }
- },
- "open_field_editor_edit": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the editor flyout to edit a field from within Lens."
+ "description": "Number of times the percentile function was selected"
}
},
- "open_field_editor_add": {
+ "indexpattern_dimension_operation_last_value": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the editor flyout to add a field from within Lens."
+ "description": "Number of times the last value function was selected"
}
},
- "save_field_edit": {
+ "indexpattern_dimension_operation_cumulative_sum": {
"type": "long",
"_meta": {
- "description": "Number of times the user edited a field from within Lens."
+ "description": "Number of times the cumulative sum function was selected"
}
},
- "save_field_add": {
+ "indexpattern_dimension_operation_counter_rate": {
"type": "long",
"_meta": {
- "description": "Number of times the user added a field from within Lens."
+ "description": "Number of times the counter rate function was selected"
}
},
- "open_field_delete_modal": {
+ "indexpattern_dimension_operation_derivative": {
"type": "long",
"_meta": {
- "description": "Number of times the user opened the field delete modal from within Lens."
+ "description": "Number of times the derivative function was selected"
}
},
- "delete_field": {
+ "indexpattern_dimension_operation_moving_average": {
"type": "long",
"_meta": {
- "description": "Number of times the user deleted a field from within Lens."
+ "description": "Number of times the moving average function was selected"
}
}
}
diff --git a/x-pack/plugins/timelines/.eslintrc.js b/x-pack/plugins/timelines/.eslintrc.js
new file mode 100644
index 0000000000000..b267018448ba6
--- /dev/null
+++ b/x-pack/plugins/timelines/.eslintrc.js
@@ -0,0 +1,7 @@
+module.exports = {
+ root: true,
+ extends: ['@elastic/eslint-config-kibana', 'plugin:@elastic/eui/recommended'],
+ rules: {
+ '@kbn/eslint/require-license-header': 'off',
+ },
+};
diff --git a/x-pack/plugins/timelines/.i18nrc.json b/x-pack/plugins/timelines/.i18nrc.json
new file mode 100644
index 0000000000000..4fe01ccc7bc69
--- /dev/null
+++ b/x-pack/plugins/timelines/.i18nrc.json
@@ -0,0 +1,7 @@
+{
+ "prefix": "timelines",
+ "paths": {
+ "timelines": "."
+ },
+ "translations": ["translations/ja-JP.json"]
+}
diff --git a/x-pack/plugins/timelines/README.md b/x-pack/plugins/timelines/README.md
new file mode 100644
index 0000000000000..441a505903698
--- /dev/null
+++ b/x-pack/plugins/timelines/README.md
@@ -0,0 +1,11 @@
+# timelines
+Timelines is a plugin that provides a grid component with accompanying server side apis to help users identify events of interest and perform root cause analysis within Kibana.
+
+
+## Using timelines in another plugin
+- Add `TimelinesPluginSetup` to Kibana plugin `SetupServices` dependencies:
+
+```ts
+timelines: TimelinesPluginSetup;
+```
+- Once `timelines` is added as a required plugin in the consuming plugin's kibana.json, timeline functionality will be available as any other kibana plugin, ie PluginSetupDependencies.timelines.getTimeline()
diff --git a/x-pack/plugins/timelines/common/index.ts b/x-pack/plugins/timelines/common/index.ts
new file mode 100644
index 0000000000000..2354c513f73b8
--- /dev/null
+++ b/x-pack/plugins/timelines/common/index.ts
@@ -0,0 +1,2 @@
+export const PLUGIN_ID = 'timelines';
+export const PLUGIN_NAME = 'timelines';
diff --git a/x-pack/plugins/timelines/kibana.json b/x-pack/plugins/timelines/kibana.json
new file mode 100644
index 0000000000000..552ddfd25ce73
--- /dev/null
+++ b/x-pack/plugins/timelines/kibana.json
@@ -0,0 +1,10 @@
+{
+ "id": "timelines",
+ "version": "1.0.0",
+ "kibanaVersion": "kibana",
+ "configPath": ["xpack", "timelines"],
+ "server": true,
+ "ui": true,
+ "requiredPlugins": [],
+ "optionalPlugins": []
+}
diff --git a/x-pack/plugins/timelines/public/components/index.tsx b/x-pack/plugins/timelines/public/components/index.tsx
new file mode 100644
index 0000000000000..3388b3c44baff
--- /dev/null
+++ b/x-pack/plugins/timelines/public/components/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { FormattedMessage, I18nProvider } from '@kbn/i18n/react';
+
+import { PLUGIN_NAME } from '../../common';
+import { TimelineProps } from '../types';
+
+export const Timeline = (props: TimelineProps) => {
+ return (
+
+
+
+
+
+ );
+};
+
+// eslint-disable-next-line import/no-default-export
+export { Timeline as default };
diff --git a/x-pack/plugins/timelines/public/index.scss b/x-pack/plugins/timelines/public/index.scss
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/x-pack/plugins/timelines/public/index.ts b/x-pack/plugins/timelines/public/index.ts
new file mode 100644
index 0000000000000..b535def809de3
--- /dev/null
+++ b/x-pack/plugins/timelines/public/index.ts
@@ -0,0 +1,11 @@
+import './index.scss';
+
+import { PluginInitializerContext } from 'src/core/public';
+import { TimelinesPlugin } from './plugin';
+
+// This exports static code and TypeScript types,
+// as well as, Kibana Platform `plugin()` initializer.
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new TimelinesPlugin(initializerContext);
+}
+export { TimelinesPluginSetup } from './types';
diff --git a/x-pack/plugins/timelines/public/methods/index.tsx b/x-pack/plugins/timelines/public/methods/index.tsx
new file mode 100644
index 0000000000000..f999e14ce910c
--- /dev/null
+++ b/x-pack/plugins/timelines/public/methods/index.tsx
@@ -0,0 +1,19 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React, { lazy, Suspense } from 'react';
+import { EuiLoadingSpinner } from '@elastic/eui';
+import { TimelineProps } from '../types';
+
+export const getTimelineLazy = (props: TimelineProps) => {
+ const TimelineLazy = lazy(() => import('../components'));
+ return (
+ }>
+
+
+ );
+};
diff --git a/x-pack/plugins/timelines/public/plugin.ts b/x-pack/plugins/timelines/public/plugin.ts
new file mode 100644
index 0000000000000..7e90d9467fefd
--- /dev/null
+++ b/x-pack/plugins/timelines/public/plugin.ts
@@ -0,0 +1,24 @@
+import { CoreSetup, Plugin, PluginInitializerContext } from '../../../../src/core/public';
+import { TimelinesPluginSetup, TimelineProps } from './types';
+import { getTimelineLazy } from './methods';
+
+export class TimelinesPlugin implements Plugin {
+ constructor(private readonly initializerContext: PluginInitializerContext) {}
+
+ public setup(core: CoreSetup): TimelinesPluginSetup {
+ const config = this.initializerContext.config.get<{ enabled: boolean }>();
+ if (!config.enabled) {
+ return {};
+ }
+
+ return {
+ getTimeline: (props: TimelineProps) => {
+ return getTimelineLazy(props);
+ },
+ };
+ }
+
+ public start() {}
+
+ public stop() {}
+}
diff --git a/x-pack/plugins/timelines/public/types.ts b/x-pack/plugins/timelines/public/types.ts
new file mode 100644
index 0000000000000..b199b45902718
--- /dev/null
+++ b/x-pack/plugins/timelines/public/types.ts
@@ -0,0 +1,9 @@
+import { ReactElement } from 'react';
+
+export interface TimelinesPluginSetup {
+ getTimeline?: (props: TimelineProps) => ReactElement;
+}
+
+export interface TimelineProps {
+ timelineId: string;
+}
diff --git a/x-pack/plugins/timelines/server/config.ts b/x-pack/plugins/timelines/server/config.ts
new file mode 100644
index 0000000000000..633a95b8f91a7
--- /dev/null
+++ b/x-pack/plugins/timelines/server/config.ts
@@ -0,0 +1,13 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { TypeOf, schema } from '@kbn/config-schema';
+
+export const ConfigSchema = schema.object({
+ enabled: schema.boolean({ defaultValue: false }),
+});
+
+export type ConfigType = TypeOf;
diff --git a/x-pack/plugins/timelines/server/index.ts b/x-pack/plugins/timelines/server/index.ts
new file mode 100644
index 0000000000000..32de97be2704a
--- /dev/null
+++ b/x-pack/plugins/timelines/server/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License;
+ * you may not use this file except in compliance with the Elastic License.
+ */
+
+import { PluginInitializerContext } from '../../../../src/core/server';
+import { TimelinesPlugin } from './plugin';
+import { ConfigSchema } from './config';
+
+export const config = {
+ schema: ConfigSchema,
+ exposeToBrowser: {
+ enabled: true,
+ },
+};
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new TimelinesPlugin(initializerContext);
+}
+
+export { TimelinesPluginSetup, TimelinesPluginStart } from './types';
diff --git a/x-pack/plugins/timelines/server/plugin.ts b/x-pack/plugins/timelines/server/plugin.ts
new file mode 100644
index 0000000000000..3e330b19b7fdb
--- /dev/null
+++ b/x-pack/plugins/timelines/server/plugin.ts
@@ -0,0 +1,35 @@
+import {
+ PluginInitializerContext,
+ CoreSetup,
+ CoreStart,
+ Plugin,
+ Logger,
+} from '../../../../src/core/server';
+
+import { TimelinesPluginSetup, TimelinesPluginStart } from './types';
+import { defineRoutes } from './routes';
+
+export class TimelinesPlugin implements Plugin {
+ private readonly logger: Logger;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.logger = initializerContext.logger.get();
+ }
+
+ public setup(core: CoreSetup) {
+ this.logger.debug('timelines: Setup');
+ const router = core.http.createRouter();
+
+ // Register server side APIs
+ defineRoutes(router);
+
+ return {};
+ }
+
+ public start(core: CoreStart) {
+ this.logger.debug('timelines: Started');
+ return {};
+ }
+
+ public stop() {}
+}
diff --git a/x-pack/plugins/timelines/server/routes/index.ts b/x-pack/plugins/timelines/server/routes/index.ts
new file mode 100644
index 0000000000000..edb10c579b30b
--- /dev/null
+++ b/x-pack/plugins/timelines/server/routes/index.ts
@@ -0,0 +1,17 @@
+import { IRouter } from '../../../../../src/core/server';
+
+export function defineRoutes(router: IRouter) {
+ router.get(
+ {
+ path: '/api/timeline/example',
+ validate: false,
+ },
+ async (context, request, response) => {
+ return response.ok({
+ body: {
+ time: new Date().toISOString(),
+ },
+ });
+ }
+ );
+}
diff --git a/x-pack/plugins/timelines/server/types.ts b/x-pack/plugins/timelines/server/types.ts
new file mode 100644
index 0000000000000..cb544562b79b4
--- /dev/null
+++ b/x-pack/plugins/timelines/server/types.ts
@@ -0,0 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface TimelinesPluginSetup {}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface TimelinesPluginStart {}
diff --git a/x-pack/plugins/timelines/tsconfig.json b/x-pack/plugins/timelines/tsconfig.json
new file mode 100644
index 0000000000000..67e606e798c03
--- /dev/null
+++ b/x-pack/plugins/timelines/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "composite": true,
+ "outDir": "./target/types",
+ "emitDeclarationOnly": true,
+ "declaration": true,
+ "declarationMap": true
+ },
+ "include": [
+ // add all the folders contains files to be compiled
+ "common/**/*",
+ "public/**/*",
+ "server/**/*"
+ ],
+ "references": [
+ { "path": "../../../src/core/tsconfig.json" },
+ ]
+}
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 8d223e730c5fa..b5cd924f480f9 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -3027,7 +3027,6 @@
"kibana-react.tableListView.listing.listingLimitExceeded.advancedSettingsLinkText": "高度な設定",
"kibana-react.tableListView.listing.listingLimitExceededDescription": "{totalItems} 件の {entityNamePlural} がありますが、{listingLimitText} の設定により {listingLimitValue} 件までしか下の表に表示できません。{advancedSettingsLink} の下でこの設定を変更できます。",
"kibana-react.tableListView.listing.listingLimitExceededTitle": "リスティング制限超過",
- "kibana-react.tableListView.listing.noAvailableItemsMessage": "利用可能な {entityNamePlural} がありません。",
"kibana-react.tableListView.listing.noMatchedItemsMessage": "検索条件に一致する {entityNamePlural} がありません。",
"kibana-react.tableListView.listing.table.actionTitle": "アクション",
"kibana-react.tableListView.listing.table.editActionDescription": "編集",
@@ -12579,7 +12578,6 @@
"xpack.maps.mapListing.descriptionFieldTitle": "説明",
"xpack.maps.mapListing.entityName": "マップ",
"xpack.maps.mapListing.entityNamePlural": "マップ",
- "xpack.maps.mapListing.errorAttemptingToLoadSavedMaps": "マップを読み込めません",
"xpack.maps.mapListing.titleFieldTitle": "タイトル",
"xpack.maps.maps.choropleth.rightSourcePlaceholder": "インデックスパターンを選択",
"xpack.maps.mapSavedObjectLabel": "マップ",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 269926a607d95..58119a0739812 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -3048,7 +3048,6 @@
"kibana-react.tableListView.listing.listingLimitExceeded.advancedSettingsLinkText": "高级设置",
"kibana-react.tableListView.listing.listingLimitExceededDescription": "您有 {totalItems} 个{entityNamePlural},但您的“{listingLimitText}”设置阻止下表显示 {listingLimitValue} 个以上。您可以在“{advancedSettingsLink}”下更改此设置。",
"kibana-react.tableListView.listing.listingLimitExceededTitle": "已超过列表限制",
- "kibana-react.tableListView.listing.noAvailableItemsMessage": "没有可用的{entityNamePlural}。",
"kibana-react.tableListView.listing.noMatchedItemsMessage": "没有任何{entityNamePlural}匹配您的搜索。",
"kibana-react.tableListView.listing.table.actionTitle": "操作",
"kibana-react.tableListView.listing.table.editActionDescription": "编辑",
@@ -12744,7 +12743,6 @@
"xpack.maps.mapListing.descriptionFieldTitle": "描述",
"xpack.maps.mapListing.entityName": "地图",
"xpack.maps.mapListing.entityNamePlural": "地图",
- "xpack.maps.mapListing.errorAttemptingToLoadSavedMaps": "无法加载地图",
"xpack.maps.mapListing.titleFieldTitle": "标题",
"xpack.maps.maps.choropleth.rightSourcePlaceholder": "选择索引模式",
"xpack.maps.mapSavedObjectLabel": "地图",
diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx
index f2da38091e37f..6706a435c7b6b 100644
--- a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx
@@ -26,7 +26,7 @@ import {
import { MAP_SAVED_OBJECT_TYPE } from '../../../../../../../maps/public';
import { MapToolTipComponent } from './map_tool_tip';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { RenderTooltipContentParams } from '../../../../../../../maps/public/classes/tooltips/tooltip_property';
+import type { RenderTooltipContentParams } from '../../../../../../../maps/public/classes/tooltips/tooltip_property';
export interface EmbeddedMapProps {
upPoints: LocationPoint[];
diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx
index f2d1227fe870e..c03ed94f8c544 100644
--- a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx
+++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx
@@ -22,8 +22,7 @@ import { AppState } from '../../../../../state';
import { monitorLocationsSelector } from '../../../../../state/selectors';
import { useMonitorId } from '../../../../../hooks';
import { MonitorLocation } from '../../../../../../common/runtime_types/monitor';
-// eslint-disable-next-line @kbn/eslint/no-restricted-paths
-import { RenderTooltipContentParams } from '../../../../../../../maps/public/classes/tooltips/tooltip_property';
+import type { RenderTooltipContentParams } from '../../../../../../../maps/public';
import { formatAvailabilityValue } from '../../availability_reporting/availability_reporting';
import { LastCheckLabel } from '../../translations';
diff --git a/x-pack/test/api_integration/apis/management/rollup/rollup.js b/x-pack/test/api_integration/apis/management/rollup/rollup.js
index 4cb2ef6ea0fa0..a556c8071ca80 100644
--- a/x-pack/test/api_integration/apis/management/rollup/rollup.js
+++ b/x-pack/test/api_integration/apis/management/rollup/rollup.js
@@ -24,7 +24,8 @@ export default function ({ getService }) {
cleanUp,
} = registerHelpers(getService);
- describe('jobs', () => {
+ // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/96002
+ describe.skip('jobs', () => {
after(() => cleanUp());
describe('indices', () => {
diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts
index a7925fa756693..f0b173d2d4c48 100644
--- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts
+++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_threat_matching.ts
@@ -317,6 +317,16 @@ export default ({ getService }: FtrProviderContext) => {
{
description: "domain should match the auditbeat hosts' data's source.ip",
domain: '159.89.119.67',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.595350Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978783/',
+ type: 'indicator',
+ },
first_seen: '2021-01-26T11:09:04.000Z',
matched: {
atomic: '159.89.119.67',
@@ -339,6 +349,16 @@ export default ({ getService }: FtrProviderContext) => {
{
description: "domain should match the auditbeat hosts' data's source.ip",
domain: '159.89.119.67',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.595350Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978783/',
+ type: 'indicator',
+ },
first_seen: '2021-01-26T11:09:04.000Z',
matched: {
atomic: '159.89.119.67',
@@ -412,6 +432,16 @@ export default ({ getService }: FtrProviderContext) => {
port: 57324,
provider: 'geenensp',
type: 'url',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
{
description: 'this should match auditbeat/hosts on ip',
@@ -426,6 +456,16 @@ export default ({ getService }: FtrProviderContext) => {
},
provider: 'other_provider',
type: 'ip',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
]);
});
@@ -492,6 +532,16 @@ export default ({ getService }: FtrProviderContext) => {
port: 57324,
provider: 'geenensp',
type: 'url',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
// We do not merge matched indicators during enrichment, so in
// certain circumstances a given indicator document could appear
@@ -512,6 +562,16 @@ export default ({ getService }: FtrProviderContext) => {
port: 57324,
provider: 'geenensp',
type: 'url',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
{
description: 'this should match auditbeat/hosts on ip',
@@ -526,6 +586,16 @@ export default ({ getService }: FtrProviderContext) => {
},
provider: 'other_provider',
type: 'ip',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
]);
});
@@ -600,6 +670,16 @@ export default ({ getService }: FtrProviderContext) => {
full: 'http://159.89.119.67:59600/bin.sh',
scheme: 'http',
},
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.595350Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978783/',
+ type: 'indicator',
+ },
},
]);
@@ -621,6 +701,16 @@ export default ({ getService }: FtrProviderContext) => {
full: 'http://159.89.119.67:59600/bin.sh',
scheme: 'http',
},
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.595350Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978783/',
+ type: 'indicator',
+ },
},
{
description: 'this should match auditbeat/hosts on both port and ip',
@@ -636,6 +726,16 @@ export default ({ getService }: FtrProviderContext) => {
port: 57324,
provider: 'geenensp',
type: 'url',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
{
description: 'this should match auditbeat/hosts on both port and ip',
@@ -651,6 +751,16 @@ export default ({ getService }: FtrProviderContext) => {
port: 57324,
provider: 'geenensp',
type: 'url',
+ event: {
+ category: 'threat',
+ created: '2021-01-26T11:09:05.529Z',
+ dataset: 'threatintel.abuseurl',
+ ingested: '2021-01-26T11:09:06.616763Z',
+ kind: 'enrichment',
+ module: 'threatintel',
+ reference: 'https://urlhaus.abuse.ch/url/978782/',
+ type: 'indicator',
+ },
},
]);
});
diff --git a/x-pack/test/fleet_api_integration/apis/agents/status.ts b/x-pack/test/fleet_api_integration/apis/agents/status.ts
index 3245b9a459fb1..f79ff15b64d33 100644
--- a/x-pack/test/fleet_api_integration/apis/agents/status.ts
+++ b/x-pack/test/fleet_api_integration/apis/agents/status.ts
@@ -79,6 +79,7 @@ export default function ({ getService }: FtrProviderContext) {
offline: 1,
updating: 1,
other: 1,
+ inactive: 0,
},
});
});
diff --git a/x-pack/test/functional/apps/dashboard/feature_controls/index.ts b/x-pack/test/functional/apps/dashboard/feature_controls/index.ts
index 38d139c59430e..3b32ea031f6e2 100644
--- a/x-pack/test/functional/apps/dashboard/feature_controls/index.ts
+++ b/x-pack/test/functional/apps/dashboard/feature_controls/index.ts
@@ -11,6 +11,7 @@ export default function ({ loadTestFile }: FtrProviderContext) {
describe('feature controls', function () {
this.tags(['skipFirefox']);
loadTestFile(require.resolve('./dashboard_security'));
+ loadTestFile(require.resolve('./time_to_visualize_security'));
loadTestFile(require.resolve('./dashboard_spaces'));
});
}
diff --git a/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts b/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts
new file mode 100644
index 0000000000000..3ebc53cc7cf27
--- /dev/null
+++ b/x-pack/test/functional/apps/dashboard/feature_controls/time_to_visualize_security.ts
@@ -0,0 +1,233 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+
+export default function ({ getPageObjects, getService }: FtrProviderContext) {
+ const PageObjects = getPageObjects([
+ 'timeToVisualize',
+ 'timePicker',
+ 'dashboard',
+ 'visEditor',
+ 'visualize',
+ 'security',
+ 'common',
+ 'header',
+ 'lens',
+ ]);
+
+ const dashboardVisualizations = getService('dashboardVisualizations');
+ const dashboardPanelActions = getService('dashboardPanelActions');
+ const dashboardExpect = getService('dashboardExpect');
+ const testSubjects = getService('testSubjects');
+ const esArchiver = getService('esArchiver');
+ const security = getService('security');
+ const find = getService('find');
+
+ describe('dashboard time to visualize security', () => {
+ before(async () => {
+ await esArchiver.load('dashboard/feature_controls/security');
+ await esArchiver.loadIfNeeded('logstash_functional');
+
+ // ensure we're logged out so we can login as the appropriate users
+ await PageObjects.security.forceLogout();
+
+ await security.role.create('dashboard_write_vis_read', {
+ elasticsearch: {
+ indices: [{ names: ['logstash-*'], privileges: ['read', 'view_index_metadata'] }],
+ },
+ kibana: [
+ {
+ feature: {
+ dashboard: ['all'],
+ visualize: ['read'],
+ },
+ spaces: ['*'],
+ },
+ ],
+ });
+
+ await security.user.create('dashboard_write_vis_read_user', {
+ password: 'dashboard_write_vis_read_user-password',
+ roles: ['dashboard_write_vis_read'],
+ full_name: 'test user',
+ });
+
+ await PageObjects.security.login(
+ 'dashboard_write_vis_read_user',
+ 'dashboard_write_vis_read_user-password',
+ {
+ expectSpaceSelector: false,
+ }
+ );
+ });
+
+ after(async () => {
+ await security.role.delete('dashboard_write_vis_read');
+ await security.user.delete('dashboard_write_vis_read_user');
+
+ await esArchiver.unload('dashboard/feature_controls/security');
+
+ // logout, so the other tests don't accidentally run as the custom users we're testing below
+ await PageObjects.security.forceLogout();
+ });
+
+ describe('lens by value works without library save permissions', () => {
+ before(async () => {
+ await PageObjects.common.navigateToApp('dashboard');
+ await PageObjects.dashboard.preserveCrossAppState();
+ await PageObjects.dashboard.clickNewDashboard();
+ });
+
+ it('can add a lens panel by value', async () => {
+ await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
+ await PageObjects.lens.createAndAddLensFromDashboard({});
+ const newPanelCount = await PageObjects.dashboard.getPanelCount();
+ expect(newPanelCount).to.eql(1);
+ });
+
+ it('edits to a by value lens panel are properly applied', async () => {
+ await PageObjects.dashboard.waitForRenderComplete();
+ await dashboardPanelActions.openContextMenu();
+ await dashboardPanelActions.clickEdit();
+ await PageObjects.lens.switchToVisualization('donut');
+ await PageObjects.lens.saveAndReturn();
+ await PageObjects.dashboard.waitForRenderComplete();
+
+ const pieExists = await find.existsByCssSelector('.lnsPieExpression__container');
+ expect(pieExists).to.be(true);
+ });
+
+ it('disables save to library button without visualize save permissions', async () => {
+ await PageObjects.dashboard.waitForRenderComplete();
+ await dashboardPanelActions.openContextMenu();
+ await dashboardPanelActions.clickEdit();
+ const saveButton = await testSubjects.find('lnsApp_saveButton');
+ expect(await saveButton.getAttribute('disabled')).to.equal('true');
+ await PageObjects.lens.saveAndReturn();
+ await PageObjects.timeToVisualize.resetNewDashboard();
+ });
+
+ it('should allow new lens to be added by value, but not by reference', async () => {
+ await PageObjects.visualize.navigateToNewVisualization();
+ await PageObjects.visualize.clickVisType('lens');
+ await PageObjects.lens.goToTimeRange();
+
+ await PageObjects.lens.configureDimension({
+ dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension',
+ operation: 'average',
+ field: 'bytes',
+ });
+
+ await PageObjects.lens.switchToVisualization('lnsMetric');
+
+ await PageObjects.lens.waitForVisualization();
+ await PageObjects.lens.assertMetric('Average of bytes', '5,727.322');
+
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await testSubjects.click('lnsApp_saveButton');
+
+ const libraryCheckbox = await find.byCssSelector('#add-to-library-checkbox');
+ expect(await libraryCheckbox.getAttribute('disabled')).to.equal('true');
+
+ await PageObjects.timeToVisualize.saveFromModal('New Lens from Modal', {
+ addToDashboard: 'new',
+ saveAsNew: true,
+ saveToLibrary: false,
+ });
+
+ await PageObjects.dashboard.waitForRenderComplete();
+
+ await PageObjects.lens.assertMetric('Average of bytes', '5,727.322');
+ const isLinked = await PageObjects.timeToVisualize.libraryNotificationExists(
+ 'New Lens from Modal'
+ );
+ expect(isLinked).to.be(false);
+
+ const panelCount = await PageObjects.dashboard.getPanelCount();
+ expect(panelCount).to.eql(1);
+
+ await PageObjects.timeToVisualize.resetNewDashboard();
+ });
+ });
+
+ describe('visualize by value works without library save permissions', () => {
+ const originalMarkdownText = 'Original markdown text';
+ const modifiedMarkdownText = 'Modified markdown text';
+
+ before(async () => {
+ await PageObjects.common.navigateToApp('dashboard');
+ await PageObjects.dashboard.preserveCrossAppState();
+ await PageObjects.dashboard.clickNewDashboard();
+ });
+
+ it('can add a markdown panel by value', async () => {
+ await PageObjects.common.navigateToApp('dashboard');
+ await PageObjects.dashboard.clickNewDashboard();
+ await PageObjects.dashboard.waitForRenderComplete();
+
+ await testSubjects.click('dashboardAddNewPanelButton');
+ await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
+ await PageObjects.visualize.clickMarkdownWidget();
+ await PageObjects.visEditor.setMarkdownTxt(originalMarkdownText);
+ await PageObjects.visEditor.clickGo();
+
+ await PageObjects.visualize.saveVisualizationAndReturn();
+ const newPanelCount = await PageObjects.dashboard.getPanelCount();
+ expect(newPanelCount).to.eql(1);
+ });
+
+ it('edits to a by value visualize panel are properly applied', async () => {
+ await dashboardPanelActions.openContextMenu();
+ await dashboardPanelActions.clickEdit();
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await PageObjects.visEditor.setMarkdownTxt(modifiedMarkdownText);
+ await PageObjects.visEditor.clickGo();
+ await PageObjects.visualize.saveVisualizationAndReturn();
+
+ await PageObjects.dashboard.waitForRenderComplete();
+ const markdownText = await testSubjects.find('markdownBody');
+ expect(await markdownText.getVisibleText()).to.eql(modifiedMarkdownText);
+
+ const newPanelCount = PageObjects.dashboard.getPanelCount();
+ expect(newPanelCount).to.eql(1);
+ });
+
+ it('disables save to library button without visualize save permissions', async () => {
+ await dashboardPanelActions.openContextMenu();
+ await dashboardPanelActions.clickEdit();
+ await PageObjects.header.waitUntilLoadingHasFinished();
+ await testSubjects.missingOrFail('visualizeSaveButton');
+ await PageObjects.visualize.saveVisualizationAndReturn();
+ await PageObjects.timeToVisualize.resetNewDashboard();
+ });
+
+ it('should allow new visualization to be added by value, but not by reference', async function () {
+ await PageObjects.visualize.navigateToNewAggBasedVisualization();
+ await PageObjects.visualize.clickMetric();
+ await PageObjects.visualize.clickNewSearch();
+ await PageObjects.timePicker.setDefaultAbsoluteRange();
+
+ await testSubjects.click('visualizeSaveButton');
+
+ await PageObjects.visualize.ensureSavePanelOpen();
+ const libraryCheckbox = await find.byCssSelector('#add-to-library-checkbox');
+ expect(await libraryCheckbox.getAttribute('disabled')).to.equal('true');
+
+ await PageObjects.timeToVisualize.saveFromModal('My New Vis 1', {
+ addToDashboard: 'new',
+ });
+
+ await PageObjects.dashboard.waitForRenderComplete();
+ await dashboardExpect.metricValuesExist(['14,005']);
+ const panelCount = await PageObjects.dashboard.getPanelCount();
+ expect(panelCount).to.eql(1);
+ });
+ });
+ });
+}
diff --git a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts
index d4a909f6a0474..c437cfaa8f5dc 100644
--- a/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts
+++ b/x-pack/test/functional/apps/dashboard/reporting/download_csv.ts
@@ -50,7 +50,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await testSubjects.existOrFail('csvDownloadStarted'); // validate toast panel
};
- describe('Download CSV', () => {
+ // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/96000
+ describe.skip('Download CSV', () => {
before('initialize tests', async () => {
log.debug('ReportingPage:initTests');
await browser.setWindowSize(1600, 850);
diff --git a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap
index 5ddef936b41ae..baa49cb6f9d81 100644
--- a/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap
+++ b/x-pack/test/functional/apps/discover/__snapshots__/reporting.snap
@@ -71,7 +71,7 @@ exports[`discover Discover CSV Export Generate CSV: new search generates a repor
24.5
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan
+}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan
"
`;
@@ -83,6 +83,6 @@ exports[`discover Discover CSV Export Generate CSV: new search generates a repor
24.5
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan
+}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan
"
`;
diff --git a/x-pack/test/functional/apps/discover/reporting.ts b/x-pack/test/functional/apps/discover/reporting.ts
index 9acb4c311c113..d7dd961e2f103 100644
--- a/x-pack/test/functional/apps/discover/reporting.ts
+++ b/x-pack/test/functional/apps/discover/reporting.ts
@@ -21,8 +21,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await kibanaServer.uiSettings.update({ 'discover:searchFieldsFromSource': setValue });
};
- // Failing: See https://github.com/elastic/kibana/issues/95592
- describe.skip('Discover CSV Export', () => {
+ describe('Discover CSV Export', () => {
before('initialize tests', async () => {
log.debug('ReportingPage:initTests');
await esArchiver.load('reporting/ecommerce');
diff --git a/x-pack/test/functional/apps/security/users.js b/x-pack/test/functional/apps/security/users.js
index 0cab12bc6672f..250a2d4ed71f9 100644
--- a/x-pack/test/functional/apps/security/users.js
+++ b/x-pack/test/functional/apps/security/users.js
@@ -12,7 +12,8 @@ export default function ({ getService, getPageObjects }) {
const config = getService('config');
const log = getService('log');
- describe('users', function () {
+ // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/96001
+ describe.skip('users', function () {
before(async () => {
log.debug('users');
await PageObjects.settings.navigateTo();
diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts
index 4c085cbb77045..7b760dfb8b6a1 100644
--- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts
+++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alerts_list.ts
@@ -54,7 +54,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await testSubjects.click('rulesTab');
}
- describe('alerts list', function () {
+ // FLAKY: https://github.com/elastic/kibana/issues/95591
+ describe.skip('alerts list', function () {
before(async () => {
await pageObjects.common.navigateToApp('triggersActions');
await testSubjects.click('rulesTab');
diff --git a/x-pack/test/plugin_functional/config.ts b/x-pack/test/plugin_functional/config.ts
index 5b846e414bd4c..104d11eb87f7c 100644
--- a/x-pack/test/plugin_functional/config.ts
+++ b/x-pack/test/plugin_functional/config.ts
@@ -30,6 +30,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
testFiles: [
resolve(__dirname, './test_suites/resolver'),
resolve(__dirname, './test_suites/global_search'),
+ resolve(__dirname, './test_suites/timelines'),
],
services,
@@ -47,6 +48,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
KIBANA_ROOT,
'test/plugin_functional/plugins/core_provider_plugin'
)}`,
+ '--xpack.timelines.enabled=true',
...plugins.map((pluginDir) => `--plugin-path=${resolve(__dirname, 'plugins', pluginDir)}`),
],
},
@@ -60,6 +62,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
resolverTest: {
pathname: '/app/resolverTest',
},
+ timelineTest: {
+ pathname: '/app/timelinesTest',
+ },
},
// choose where esArchiver should load archives from
diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json b/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json
new file mode 100644
index 0000000000000..85c2639ef7d47
--- /dev/null
+++ b/x-pack/test/plugin_functional/plugins/timelines_test/kibana.json
@@ -0,0 +1,12 @@
+{
+ "id": "timelinesTest",
+ "version": "1.0.0",
+ "kibanaVersion": "kibana",
+ "configPath": ["xpack", "timelinesTest"],
+ "requiredPlugins": ["timelines"],
+ "requiredBundles": [
+ "kibanaReact"
+ ],
+ "server": false,
+ "ui": true
+}
diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx b/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx
new file mode 100644
index 0000000000000..a6772c3b0bb5b
--- /dev/null
+++ b/x-pack/test/plugin_functional/plugins/timelines_test/public/applications/timelines_test/index.tsx
@@ -0,0 +1,60 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { Router } from 'react-router-dom';
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { AppMountParameters, CoreStart } from 'kibana/public';
+import { I18nProvider } from '@kbn/i18n/react';
+import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public';
+import { TimelinesPluginSetup } from '../../../../../../../plugins/timelines/public';
+
+/**
+ * Render the Timeline Test app. Returns a cleanup function.
+ */
+export function renderApp(
+ coreStart: CoreStart,
+ parameters: AppMountParameters,
+ timelinesPluginSetup: TimelinesPluginSetup
+) {
+ ReactDOM.render(
+ ,
+ parameters.element
+ );
+
+ return () => {
+ ReactDOM.unmountComponentAtNode(parameters.element);
+ };
+}
+
+const AppRoot = React.memo(
+ ({
+ coreStart,
+ parameters,
+ timelinesPluginSetup,
+ }: {
+ coreStart: CoreStart;
+ parameters: AppMountParameters;
+ timelinesPluginSetup: TimelinesPluginSetup;
+ }) => {
+ return (
+
+
+
+ {(timelinesPluginSetup.getTimeline &&
+ timelinesPluginSetup.getTimeline({ timelineId: 'test' })) ??
+ null}
+
+
+
+ );
+ }
+);
diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts b/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts
new file mode 100644
index 0000000000000..5f038b5b933e6
--- /dev/null
+++ b/x-pack/test/plugin_functional/plugins/timelines_test/public/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { PluginInitializer } from 'kibana/public';
+import {
+ TimelinesTestPlugin,
+ TimelinesTestPluginSetupDependencies,
+ TimelinesTestPluginStartDependencies,
+} from './plugin';
+
+export const plugin: PluginInitializer<
+ void,
+ void,
+ TimelinesTestPluginSetupDependencies,
+ TimelinesTestPluginStartDependencies
+> = () => new TimelinesTestPlugin();
diff --git a/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts b/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts
new file mode 100644
index 0000000000000..5cf900e194d0c
--- /dev/null
+++ b/x-pack/test/plugin_functional/plugins/timelines_test/public/plugin.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public';
+import { i18n } from '@kbn/i18n';
+import { TimelinesPluginSetup } from '../../../../../plugins/timelines/public';
+import { renderApp } from './applications/timelines_test';
+
+export type TimelinesTestPluginSetup = void;
+export type TimelinesTestPluginStart = void;
+export interface TimelinesTestPluginSetupDependencies {
+ timelines: TimelinesPluginSetup;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface TimelinesTestPluginStartDependencies {}
+
+export class TimelinesTestPlugin
+ implements
+ Plugin<
+ TimelinesTestPluginSetup,
+ void,
+ TimelinesTestPluginSetupDependencies,
+ TimelinesTestPluginStartDependencies
+ > {
+ public setup(
+ core: CoreSetup,
+ setupDependencies: TimelinesTestPluginSetupDependencies
+ ) {
+ core.application.register({
+ id: 'timelinesTest',
+ title: i18n.translate('xpack.timelinesTest.pluginTitle', {
+ defaultMessage: 'Timelines Test',
+ }),
+ mount: async (params: AppMountParameters) => {
+ const startServices = await core.getStartServices();
+ const [coreStart] = startServices;
+ const { timelines } = setupDependencies;
+
+ return renderApp(coreStart, params, timelines);
+ },
+ });
+ }
+
+ public start() {}
+}
diff --git a/x-pack/test/plugin_functional/test_suites/timelines/index.ts b/x-pack/test/plugin_functional/test_suites/timelines/index.ts
new file mode 100644
index 0000000000000..655ed9dc3898a
--- /dev/null
+++ b/x-pack/test/plugin_functional/test_suites/timelines/index.ts
@@ -0,0 +1,25 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../../ftr_provider_context';
+
+export default function ({ getPageObjects, getService }: FtrProviderContext) {
+ describe('Timelines plugin API', function () {
+ this.tags('ciGroup7');
+ const pageObjects = getPageObjects(['common']);
+ const testSubjects = getService('testSubjects');
+
+ describe('timelines plugin rendering', function () {
+ before(async () => {
+ await pageObjects.common.navigateToApp('timelineTest');
+ });
+ it('shows the timeline component on navigation', async () => {
+ await testSubjects.existOrFail('timeline-wrapper');
+ });
+ });
+ });
+}
diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap
index c7ef39f65f552..094d72942353d 100644
--- a/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap
+++ b/x-pack/test/reporting_api_integration/reporting_and_security/__snapshots__/csv_searchsource_immediate.snap
@@ -8,28 +8,28 @@ exports[`Reporting APIs CSV Generation from SearchSource Exports CSV with all fi
24.5
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.39, 32.99, 10.34, 6.11\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"79.99, 59.99, 21.99, 11.99\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"173.96\\",\\"173.96\\",4,4,order,sultan
+}\\",\\"Abu Dhabi\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Angeldale, Oceanavigations, Microlutions\\",\\"Jul 12, 2019 @ 00:00:00.000\\",716724,\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"sold_product_716724_23975, sold_product_716724_6338, sold_product_716724_14116, sold_product_716724_15290\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Men's Shoes, Men's Clothing, Women's Accessories, Men's Accessories\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0, 0, 0\\",\\"0, 0, 0, 0\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"Angeldale, Oceanavigations, Microlutions, Oceanavigations\\",\\"42.375, 33, 10.344, 6.109\\",\\"80, 60, 21.984, 11.992\\",\\"23,975, 6,338, 14,116, 15,290\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"Winter boots - cognac, Trenchcoat - black, Watch - black, Hat - light grey multicolor\\",\\"1, 1, 1, 1\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",\\"0, 0, 0, 0\\",\\"80, 60, 21.984, 11.992\\",\\"80, 60, 21.984, 11.992\\",\\"0, 0, 0, 0\\",\\"ZO0687606876, ZO0290502905, ZO0126701267, ZO0308503085\\",174,174,4,4,order,sultan
9gMtOW0BH63Xcmy432DJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",EUR,Pia,Pia,\\"Pia Richards\\",\\"Pia Richards\\",FEMALE,45,Richards,Richards,,Saturday,5,\\"pia@richards-family.zzz\\",Cannes,Europe,FR,\\"{
\\"\\"coordinates\\"\\": [
7,
43.6
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.99, 20.99\\",\\"20.99, 20.99\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.7, 9.87\\",\\"20.99, 20.99\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.99, 20.99\\",\\"20.99, 20.99\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.98\\",\\"41.98\\",2,2,order,pia
+}\\",\\"Alpes-Maritimes\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591503,\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"sold_product_591503_14761, sold_product_591503_11632\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"Women's Shoes, Women's Clothing\\",\\"Women's Shoes, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Tigress Enterprises, Pyramidustries\\",\\"Tigress Enterprises, Pyramidustries\\",\\"10.703, 9.867\\",\\"20.984, 20.984\\",\\"14,761, 11,632\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"Classic heels - blue, Summer dress - coral/pink\\",\\"1, 1\\",\\"ZO0006400064, ZO0150601506\\",\\"0, 0\\",\\"20.984, 20.984\\",\\"20.984, 20.984\\",\\"0, 0\\",\\"ZO0006400064, ZO0150601506\\",\\"41.969\\",\\"41.969\\",2,2,order,pia
BgMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Women's Clothing\\",\\"Women's Clothing\\",EUR,Brigitte,Brigitte,\\"Brigitte Meyer\\",\\"Brigitte Meyer\\",FEMALE,12,Meyer,Meyer,,Saturday,5,\\"brigitte@meyer-family.zzz\\",\\"New York\\",\\"North America\\",US,\\"{
\\"\\"coordinates\\"\\": [
-74,
40.8
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.99, 32.99\\",\\"7.99, 32.99\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.48\\",\\"7.99, 32.99\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.99, 32.99\\",\\"7.99, 32.99\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.98\\",\\"40.98\\",2,2,order,brigitte
+}\\",\\"New York\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"Jul 12, 2019 @ 00:00:00.000\\",591709,\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"sold_product_591709_20734, sold_product_591709_7539\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"Women's Clothing, Women's Clothing\\",\\"Women's Clothing, Women's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Spherecords, Tigress Enterprises\\",\\"Spherecords, Tigress Enterprises\\",\\"3.6, 17.484\\",\\"7.988, 33\\",\\"20,734, 7,539\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"Basic T-shirt - dark blue, Summer dress - scarab\\",\\"1, 1\\",\\"ZO0638206382, ZO0038800388\\",\\"0, 0\\",\\"7.988, 33\\",\\"7.988, 33\\",\\"0, 0\\",\\"ZO0638206382, ZO0038800388\\",\\"40.969\\",\\"40.969\\",2,2,order,brigitte
KQMtOW0BH63Xcmy432LJ,ecommerce,\\"-\\",\\"-\\",\\"Men's Clothing\\",\\"Men's Clothing\\",EUR,Abd,Abd,\\"Abd Mccarthy\\",\\"Abd Mccarthy\\",MALE,52,Mccarthy,Mccarthy,,Saturday,5,\\"abd@mccarthy-family.zzz\\",Cairo,Africa,EG,\\"{
\\"\\"coordinates\\"\\": [
31.3,
30.1
],
\\"\\"type\\"\\": \\"\\"Point\\"\\"
-}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.99, 12.99\\",\\"28.99, 12.99\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.34, 6.11\\",\\"28.99, 12.99\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.99, 12.99\\",\\"28.99, 12.99\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.98\\",\\"41.98\\",2,2,order,abd
+}\\",\\"Cairo Governorate\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"Jul 12, 2019 @ 00:00:00.000\\",590937,\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"sold_product_590937_14438, sold_product_590937_23607\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"Men's Clothing, Men's Clothing\\",\\"Men's Clothing, Men's Clothing\\",\\"Dec 31, 2016 @ 00:00:00.000, Dec 31, 2016 @ 00:00:00.000\\",\\"0, 0\\",\\"0, 0\\",\\"Oceanavigations, Elitelligence\\",\\"Oceanavigations, Elitelligence\\",\\"13.344, 6.109\\",\\"28.984, 12.992\\",\\"14,438, 23,607\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"Jumper - dark grey multicolor, Print T-shirt - black\\",\\"1, 1\\",\\"ZO0297602976, ZO0565605656\\",\\"0, 0\\",\\"28.984, 12.992\\",\\"28.984, 12.992\\",\\"0, 0\\",\\"ZO0297602976, ZO0565605656\\",\\"41.969\\",\\"41.969\\",2,2,order,abd
"
`;
diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts
index ffaa4cb2f8fb6..ebc7badd88f42 100644
--- a/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts
+++ b/x-pack/test/reporting_api_integration/reporting_and_security/csv_searchsource_immediate.ts
@@ -31,7 +31,7 @@ export default function ({ getService }: FtrProviderContext) {
},
};
- // Failing: See https://github.com/elastic/kibana/issues/95594
+ // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/96000
describe.skip('CSV Generation from SearchSource', () => {
before(async () => {
await kibanaServer.uiSettings.update({