diff --git a/.backportrc.json b/.backportrc.json
index 87bc3a1be583ba..8f458343c51afd 100644
--- a/.backportrc.json
+++ b/.backportrc.json
@@ -25,6 +25,7 @@
],
"targetPRLabels": ["backport"],
"branchLabelMapping": {
+ "^v8.0.0$": "master",
"^v7.9.0$": "7.x",
"^v(\\d+).(\\d+).\\d+$": "$1.$2"
}
diff --git a/.eslintignore b/.eslintignore
index fbdd70703f3c40..9de2cc28729602 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -33,6 +33,7 @@ target
/x-pack/plugins/canvas/shareable_runtime/build
/x-pack/plugins/canvas/storybook
/x-pack/plugins/monitoring/public/lib/jquery_flot
+/x-pack/plugins/reporting/server/export_types/printable_pdf/server/lib/pdf/assets/**
/x-pack/legacy/plugins/infra/common/graphql/types.ts
/x-pack/legacy/plugins/infra/public/graphql/types.ts
/x-pack/legacy/plugins/infra/server/graphql/types.ts
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e6f6e83253c8bb..47f9942162f75c 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -170,6 +170,7 @@
# Kibana Telemetry
/packages/kbn-analytics/ @elastic/kibana-telemetry
+/packages/kbn-telemetry-tools/ @elastic/kibana-telemetry
/src/plugins/kibana_usage_collection/ @elastic/kibana-telemetry
/src/plugins/newsfeed/ @elastic/kibana-telemetry
/src/plugins/telemetry/ @elastic/kibana-telemetry
@@ -177,6 +178,11 @@
/src/plugins/telemetry_management_section/ @elastic/kibana-telemetry
/src/plugins/usage_collection/ @elastic/kibana-telemetry
/x-pack/plugins/telemetry_collection_xpack/ @elastic/kibana-telemetry
+/.telemetryrc.json @elastic/kibana-telemetry
+/x-pack/.telemetryrc.json @elastic/kibana-telemetry
+src/plugins/telemetry/schema/legacy_oss_plugins.json @elastic/kibana-telemetry
+src/plugins/telemetry/schema/oss_plugins.json @elastic/kibana-telemetry
+x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @elastic/kibana-telemetry
# Kibana Alerting Services
/x-pack/plugins/alerts/ @elastic/kibana-alerting-services
diff --git a/.telemetryrc.json b/.telemetryrc.json
new file mode 100644
index 00000000000000..30643a104c1cd2
--- /dev/null
+++ b/.telemetryrc.json
@@ -0,0 +1,25 @@
+[
+ {
+ "output": "src/plugins/telemetry/schema/legacy_oss_plugins.json",
+ "root": "src/legacy/core_plugins/",
+ "exclude": [
+ "src/legacy/core_plugins/testbed",
+ "src/legacy/core_plugins/elasticsearch",
+ "src/legacy/core_plugins/tests_bundle"
+ ]
+ },
+ {
+ "output": "src/plugins/telemetry/schema/oss_plugins.json",
+ "root": "src/plugins/",
+ "exclude": [
+ "src/plugins/kibana_react/",
+ "src/plugins/testbed/",
+ "src/plugins/kibana_utils/",
+ "src/plugins/kibana_usage_collection/server/collectors/kibana/kibana_usage_collector.ts",
+ "src/plugins/kibana_usage_collection/server/collectors/application_usage/telemetry_application_usage_collector.ts",
+ "src/plugins/kibana_usage_collection/server/collectors/management/telemetry_management_collector.ts",
+ "src/plugins/kibana_usage_collection/server/collectors/ui_metric/telemetry_ui_metric_collector.ts",
+ "src/plugins/telemetry/server/collectors/usage/telemetry_usage_collector.ts"
+ ]
+ }
+]
diff --git a/docs/development/core/public/kibana-plugin-core-public.app.exactroute.md b/docs/development/core/public/kibana-plugin-core-public.app.exactroute.md
new file mode 100644
index 00000000000000..d1e0be17a92b24
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.app.exactroute.md
@@ -0,0 +1,30 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [exactRoute](./kibana-plugin-core-public.app.exactroute.md)
+
+## App.exactRoute property
+
+If set to true, the application's route will only be checked against an exact match. Defaults to `false`.
+
+Signature:
+
+```typescript
+exactRoute?: boolean;
+```
+
+## Example
+
+
+```ts
+core.application.register({
+ id: 'my_app',
+ title: 'My App'
+ exactRoute: true,
+ mount: () => { ... },
+})
+
+// '[basePath]/app/my_app' will be matched
+// '[basePath]/app/my_app/some/path' will not be matched
+
+```
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.app.md b/docs/development/core/public/kibana-plugin-core-public.app.md
index 90737d241f5484..8dd60972549f9a 100644
--- a/docs/development/core/public/kibana-plugin-core-public.app.md
+++ b/docs/development/core/public/kibana-plugin-core-public.app.md
@@ -18,5 +18,6 @@ export interface App extends AppBase
| --- | --- | --- |
| [appRoute](./kibana-plugin-core-public.app.approute.md) | string
| Override the application's routing path from /app/${id}
. Must be unique across registered applications. Should not include the base path from HTTP. |
| [chromeless](./kibana-plugin-core-public.app.chromeless.md) | boolean
| Hide the UI chrome when the application is mounted. Defaults to false
. Takes precedence over chrome service visibility settings. |
+| [exactRoute](./kibana-plugin-core-public.app.exactroute.md) | boolean
| If set to true, the application's route will only be checked against an exact match. Defaults to false
. |
| [mount](./kibana-plugin-core-public.app.mount.md) | AppMount<HistoryLocationState> | AppMountDeprecated<HistoryLocationState>
| A mount function called when the user navigates to this app's route. May have signature of [AppMount](./kibana-plugin-core-public.appmount.md) or [AppMountDeprecated](./kibana-plugin-core-public.appmountdeprecated.md). |
diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.getcustomnavlink_.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.getcustomnavlink_.md
new file mode 100644
index 00000000000000..64805eefbfea1f
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.chromestart.getcustomnavlink_.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [getCustomNavLink$](./kibana-plugin-core-public.chromestart.getcustomnavlink_.md)
+
+## ChromeStart.getCustomNavLink$() method
+
+Get an observable of the current custom nav link
+
+Signature:
+
+```typescript
+getCustomNavLink$(): Observable | undefined>;
+```
+Returns:
+
+`Observable | undefined>`
+
diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.md
index b4eadc93fe78d3..e983ad50d2afe5 100644
--- a/docs/development/core/public/kibana-plugin-core-public.chromestart.md
+++ b/docs/development/core/public/kibana-plugin-core-public.chromestart.md
@@ -55,6 +55,7 @@ core.chrome.setHelpExtension(elem => {
| [getBadge$()](./kibana-plugin-core-public.chromestart.getbadge_.md) | Get an observable of the current badge |
| [getBrand$()](./kibana-plugin-core-public.chromestart.getbrand_.md) | Get an observable of the current brand information. |
| [getBreadcrumbs$()](./kibana-plugin-core-public.chromestart.getbreadcrumbs_.md) | Get an observable of the current list of breadcrumbs |
+| [getCustomNavLink$()](./kibana-plugin-core-public.chromestart.getcustomnavlink_.md) | Get an observable of the current custom nav link |
| [getHelpExtension$()](./kibana-plugin-core-public.chromestart.gethelpextension_.md) | Get an observable of the current custom help conttent |
| [getIsNavDrawerLocked$()](./kibana-plugin-core-public.chromestart.getisnavdrawerlocked_.md) | Get an observable of the current locked state of the nav drawer. |
| [getIsVisible$()](./kibana-plugin-core-public.chromestart.getisvisible_.md) | Get an observable of the current visibility state of the chrome. |
@@ -64,6 +65,7 @@ core.chrome.setHelpExtension(elem => {
| [setBadge(badge)](./kibana-plugin-core-public.chromestart.setbadge.md) | Override the current badge |
| [setBrand(brand)](./kibana-plugin-core-public.chromestart.setbrand.md) | Set the brand configuration. |
| [setBreadcrumbs(newBreadcrumbs)](./kibana-plugin-core-public.chromestart.setbreadcrumbs.md) | Override the current set of breadcrumbs |
+| [setCustomNavLink(newCustomNavLink)](./kibana-plugin-core-public.chromestart.setcustomnavlink.md) | Override the current set of custom nav link |
| [setHelpExtension(helpExtension)](./kibana-plugin-core-public.chromestart.sethelpextension.md) | Override the current set of custom help content |
| [setHelpSupportUrl(url)](./kibana-plugin-core-public.chromestart.sethelpsupporturl.md) | Override the default support URL shown in the help menu |
| [setIsVisible(isVisible)](./kibana-plugin-core-public.chromestart.setisvisible.md) | Set the temporary visibility for the chrome. This does nothing if the chrome is hidden by default and should be used to hide the chrome for things like full-screen modes with an exit button. |
diff --git a/docs/development/core/public/kibana-plugin-core-public.chromestart.setcustomnavlink.md b/docs/development/core/public/kibana-plugin-core-public.chromestart.setcustomnavlink.md
new file mode 100644
index 00000000000000..adfb57f9c5ff25
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-core-public.chromestart.setcustomnavlink.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeStart](./kibana-plugin-core-public.chromestart.md) > [setCustomNavLink](./kibana-plugin-core-public.chromestart.setcustomnavlink.md)
+
+## ChromeStart.setCustomNavLink() method
+
+Override the current set of custom nav link
+
+Signature:
+
+```typescript
+setCustomNavLink(newCustomNavLink?: Partial): void;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| newCustomNavLink | Partial<ChromeNavLink>
| |
+
+Returns:
+
+`void`
+
diff --git a/docs/development/core/server/kibana-plugin-core-server.coresetup.md b/docs/development/core/server/kibana-plugin-core-server.coresetup.md
index e9ed5b830b6918..32221a320d2a15 100644
--- a/docs/development/core/server/kibana-plugin-core-server.coresetup.md
+++ b/docs/development/core/server/kibana-plugin-core-server.coresetup.md
@@ -22,7 +22,6 @@ export interface CoreSetupStartServicesAccessor<TPluginsStart, TStart> | [StartServicesAccessor](./kibana-plugin-core-server.startservicesaccessor.md) |
| [http](./kibana-plugin-core-server.coresetup.http.md) | HttpServiceSetup & {
resources: HttpResources;
}
| [HttpServiceSetup](./kibana-plugin-core-server.httpservicesetup.md) |
| [logging](./kibana-plugin-core-server.coresetup.logging.md) | LoggingServiceSetup
| [LoggingServiceSetup](./kibana-plugin-core-server.loggingservicesetup.md) |
-| [metrics](./kibana-plugin-core-server.coresetup.metrics.md) | MetricsServiceSetup
| [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) |
| [savedObjects](./kibana-plugin-core-server.coresetup.savedobjects.md) | SavedObjectsServiceSetup
| [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) |
| [status](./kibana-plugin-core-server.coresetup.status.md) | StatusServiceSetup
| [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) |
| [uiSettings](./kibana-plugin-core-server.coresetup.uisettings.md) | UiSettingsServiceSetup
| [UiSettingsServiceSetup](./kibana-plugin-core-server.uisettingsservicesetup.md) |
diff --git a/docs/development/core/server/kibana-plugin-core-server.coresetup.metrics.md b/docs/development/core/server/kibana-plugin-core-server.coresetup.metrics.md
deleted file mode 100644
index 77c9e867ef8ea8..00000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.coresetup.metrics.md
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CoreSetup](./kibana-plugin-core-server.coresetup.md) > [metrics](./kibana-plugin-core-server.coresetup.metrics.md)
-
-## CoreSetup.metrics property
-
-[MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md)
-
-Signature:
-
-```typescript
-metrics: MetricsServiceSetup;
-```
diff --git a/docs/development/core/server/kibana-plugin-core-server.corestart.md b/docs/development/core/server/kibana-plugin-core-server.corestart.md
index 6a6bacf1eef40b..acd23f0f473867 100644
--- a/docs/development/core/server/kibana-plugin-core-server.corestart.md
+++ b/docs/development/core/server/kibana-plugin-core-server.corestart.md
@@ -19,6 +19,7 @@ export interface CoreStart
| [capabilities](./kibana-plugin-core-server.corestart.capabilities.md) | CapabilitiesStart
| [CapabilitiesStart](./kibana-plugin-core-server.capabilitiesstart.md) |
| [elasticsearch](./kibana-plugin-core-server.corestart.elasticsearch.md) | ElasticsearchServiceStart
| [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) |
| [http](./kibana-plugin-core-server.corestart.http.md) | HttpServiceStart
| [HttpServiceStart](./kibana-plugin-core-server.httpservicestart.md) |
+| [metrics](./kibana-plugin-core-server.corestart.metrics.md) | MetricsServiceStart
| |
| [savedObjects](./kibana-plugin-core-server.corestart.savedobjects.md) | SavedObjectsServiceStart
| [SavedObjectsServiceStart](./kibana-plugin-core-server.savedobjectsservicestart.md) |
| [uiSettings](./kibana-plugin-core-server.corestart.uisettings.md) | UiSettingsServiceStart
| [UiSettingsServiceStart](./kibana-plugin-core-server.uisettingsservicestart.md) |
diff --git a/docs/development/core/server/kibana-plugin-core-server.corestart.metrics.md b/docs/development/core/server/kibana-plugin-core-server.corestart.metrics.md
new file mode 100644
index 00000000000000..a51c2f842c3464
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-core-server.corestart.metrics.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [CoreStart](./kibana-plugin-core-server.corestart.md) > [metrics](./kibana-plugin-core-server.corestart.metrics.md)
+
+## CoreStart.metrics property
+
+
+Signature:
+
+```typescript
+metrics: MetricsServiceStart;
+```
diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md
index 1a03ac5ee3d1ad..74422c82fc9ea7 100644
--- a/docs/development/core/server/kibana-plugin-core-server.md
+++ b/docs/development/core/server/kibana-plugin-core-server.md
@@ -112,7 +112,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [LoggerFactory](./kibana-plugin-core-server.loggerfactory.md) | The single purpose of LoggerFactory
interface is to define a way to retrieve a context-based logger instance. |
| [LoggingServiceSetup](./kibana-plugin-core-server.loggingservicesetup.md) | Provides APIs to plugins for customizing the plugin's logger. |
| [LogMeta](./kibana-plugin-core-server.logmeta.md) | Contextual metadata |
-| [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) | APIs to retrieves metrics gathered and exposed by the core platform. |
+| [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) | |
| [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) | |
| [OnPostAuthToolkit](./kibana-plugin-core-server.onpostauthtoolkit.md) | A tool set defining an outcome of OnPostAuth interceptor for incoming request. |
| [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. |
@@ -150,7 +150,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [SavedObjectsBulkUpdateResponse](./kibana-plugin-core-server.savedobjectsbulkupdateresponse.md) | |
| [SavedObjectsClientProviderOptions](./kibana-plugin-core-server.savedobjectsclientprovideroptions.md) | Options to control the creation of the Saved Objects Client. |
| [SavedObjectsClientWrapperOptions](./kibana-plugin-core-server.savedobjectsclientwrapperoptions.md) | Options passed to each SavedObjectsClientWrapperFactory to aid in creating the wrapper instance. |
-| [SavedObjectsComplexFieldMapping](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation. |
+| [SavedObjectsComplexFieldMapping](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation.Note: this type intentially doesn't include a type definition for defining the dynamic
mapping parameter. Saved Object fields should always inherit the dynamic: 'strict'
paramater. If you are unsure of the shape of your data use type: 'object', enabled: false
instead. |
| [SavedObjectsCoreFieldMapping](./kibana-plugin-core-server.savedobjectscorefieldmapping.md) | See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation. |
| [SavedObjectsCreateOptions](./kibana-plugin-core-server.savedobjectscreateoptions.md) | |
| [SavedObjectsDeleteByNamespaceOptions](./kibana-plugin-core-server.savedobjectsdeletebynamespaceoptions.md) | |
diff --git a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md
deleted file mode 100644
index 61107fbf20ad92..00000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) > [getOpsMetrics$](./kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md)
-
-## MetricsServiceSetup.getOpsMetrics$ property
-
-Retrieve an observable emitting the [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) gathered. The observable will emit an initial value during core's `start` phase, and a new value every fixed interval of time, based on the `opts.interval` configuration property.
-
-Signature:
-
-```typescript
-getOpsMetrics$: () => Observable;
-```
-
-## Example
-
-
-```ts
-core.metrics.getOpsMetrics$().subscribe(metrics => {
- // do something with the metrics
-})
-
-```
-
diff --git a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md
index 00045aeac74b4a..0bec919797b6f8 100644
--- a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md
+++ b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md
@@ -4,17 +4,8 @@
## MetricsServiceSetup interface
-APIs to retrieves metrics gathered and exposed by the core platform.
-
Signature:
```typescript
export interface MetricsServiceSetup
```
-
-## Properties
-
-| Property | Type | Description |
-| --- | --- | --- |
-| [getOpsMetrics$](./kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md) | () => Observable<OpsMetrics>
| Retrieve an observable emitting the [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) gathered. The observable will emit an initial value during core's start
phase, and a new value every fixed interval of time, based on the opts.interval
configuration property. |
-
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.dynamic.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.dynamic.md
deleted file mode 100644
index e63e543e68d517..00000000000000
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.dynamic.md
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [SavedObjectsComplexFieldMapping](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.md) > [dynamic](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.dynamic.md)
-
-## SavedObjectsComplexFieldMapping.dynamic property
-
-Signature:
-
-```typescript
-dynamic?: string;
-```
diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.md
index 60e62212609d9f..a7d13b0015e3fd 100644
--- a/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.md
+++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectscomplexfieldmapping.md
@@ -6,6 +6,8 @@
See [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) for documentation.
+Note: this type intentially doesn't include a type definition for defining the `dynamic` mapping parameter. Saved Object fields should always inherit the `dynamic: 'strict'` paramater. If you are unsure of the shape of your data use `type: 'object', enabled: false` instead.
+
Signature:
```typescript
@@ -16,7 +18,6 @@ export interface SavedObjectsComplexFieldMapping
| Property | Type | Description |
| --- | --- | --- |
-| [dynamic](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.dynamic.md) | string
| |
| [properties](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.properties.md) | SavedObjectsMappingProperties
| |
| [type](./kibana-plugin-core-server.savedobjectscomplexfieldmapping.type.md) | string
| |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.md
index be6af335f20cd5..6f42fb32fdb7be 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.md
@@ -28,6 +28,7 @@ export interface IFieldType
| [searchable](./kibana-plugin-plugins-data-public.ifieldtype.searchable.md) | boolean
| |
| [sortable](./kibana-plugin-plugins-data-public.ifieldtype.sortable.md) | boolean
| |
| [subType](./kibana-plugin-plugins-data-public.ifieldtype.subtype.md) | IFieldSubType
| |
+| [toSpec](./kibana-plugin-plugins-data-public.ifieldtype.tospec.md) | () => FieldSpec
| |
| [type](./kibana-plugin-plugins-data-public.ifieldtype.type.md) | string
| |
| [visualizable](./kibana-plugin-plugins-data-public.ifieldtype.visualizable.md) | boolean
| |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.tospec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.tospec.md
new file mode 100644
index 00000000000000..1fb4084c25d343
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ifieldtype.tospec.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IFieldType](./kibana-plugin-plugins-data-public.ifieldtype.md) > [toSpec](./kibana-plugin-plugins-data-public.ifieldtype.tospec.md)
+
+## IFieldType.toSpec property
+
+Signature:
+
+```typescript
+toSpec?: () => FieldSpec;
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md
index 9a93148e4a466f..d4dca48c7cd7b4 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.fields.md
@@ -7,5 +7,7 @@
Signature:
```typescript
-fields: IIndexPatternFieldList;
+fields: IIndexPatternFieldList & {
+ toSpec: () => FieldSpec[];
+ };
```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.initfromspec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.initfromspec.md
new file mode 100644
index 00000000000000..764dd116382217
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.initfromspec.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [initFromSpec](./kibana-plugin-plugins-data-public.indexpattern.initfromspec.md)
+
+## IndexPattern.initFromSpec() method
+
+Signature:
+
+```typescript
+initFromSpec(spec: IndexPatternSpec): this;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| spec | IndexPatternSpec
| |
+
+Returns:
+
+`this`
+
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md
index 8ffa7b6b36f56b..d39b384c538f1b 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md
@@ -21,7 +21,7 @@ export declare class IndexPattern implements IIndexPattern
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [fieldFormatMap](./kibana-plugin-plugins-data-public.indexpattern.fieldformatmap.md) | | any
| |
-| [fields](./kibana-plugin-plugins-data-public.indexpattern.fields.md) | | IIndexPatternFieldList
| |
+| [fields](./kibana-plugin-plugins-data-public.indexpattern.fields.md) | | IIndexPatternFieldList & {
toSpec: () => FieldSpec[];
}
| |
| [fieldsFetcher](./kibana-plugin-plugins-data-public.indexpattern.fieldsfetcher.md) | | any
| |
| [flattenHit](./kibana-plugin-plugins-data-public.indexpattern.flattenhit.md) | | any
| |
| [formatField](./kibana-plugin-plugins-data-public.indexpattern.formatfield.md) | | any
| |
@@ -30,7 +30,6 @@ export declare class IndexPattern implements IIndexPattern
| [metaFields](./kibana-plugin-plugins-data-public.indexpattern.metafields.md) | | string[]
| |
| [timeFieldName](./kibana-plugin-plugins-data-public.indexpattern.timefieldname.md) | | string | undefined
| |
| [title](./kibana-plugin-plugins-data-public.indexpattern.title.md) | | string
| |
-| [type](./kibana-plugin-plugins-data-public.indexpattern.type.md) | | string
| |
| [typeMeta](./kibana-plugin-plugins-data-public.indexpattern.typemeta.md) | | TypeMeta
| |
## Methods
@@ -49,6 +48,7 @@ export declare class IndexPattern implements IIndexPattern
| [getSourceFiltering()](./kibana-plugin-plugins-data-public.indexpattern.getsourcefiltering.md) | | |
| [getTimeField()](./kibana-plugin-plugins-data-public.indexpattern.gettimefield.md) | | |
| [init(forceFieldRefresh)](./kibana-plugin-plugins-data-public.indexpattern.init.md) | | |
+| [initFromSpec(spec)](./kibana-plugin-plugins-data-public.indexpattern.initfromspec.md) | | |
| [isTimeBased()](./kibana-plugin-plugins-data-public.indexpattern.istimebased.md) | | |
| [isTimeBasedWildcard()](./kibana-plugin-plugins-data-public.indexpattern.istimebasedwildcard.md) | | |
| [isTimeNanosBased()](./kibana-plugin-plugins-data-public.indexpattern.istimenanosbased.md) | | |
@@ -59,5 +59,6 @@ export declare class IndexPattern implements IIndexPattern
| [removeScriptedField(field)](./kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md) | | |
| [save(saveAttempts)](./kibana-plugin-plugins-data-public.indexpattern.save.md) | | |
| [toJSON()](./kibana-plugin-plugins-data-public.indexpattern.tojson.md) | | |
+| [toSpec()](./kibana-plugin-plugins-data-public.indexpattern.tospec.md) | | |
| [toString()](./kibana-plugin-plugins-data-public.indexpattern.tostring.md) | | |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.tospec.md
similarity index 53%
rename from docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md
rename to docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.tospec.md
index 58047d9e27ac63..d1a78eea660cea 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.type.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.tospec.md
@@ -1,11 +1,15 @@
-[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [type](./kibana-plugin-plugins-data-public.indexpattern.type.md)
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [toSpec](./kibana-plugin-plugins-data-public.indexpattern.tospec.md)
-## IndexPattern.type property
+## IndexPattern.toSpec() method
Signature:
```typescript
-type?: string;
+toSpec(): IndexPatternSpec;
```
+Returns:
+
+`IndexPatternSpec`
+
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md
index e1e0d58ce38c10..7a195702b6f13f 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield._constructor_.md
@@ -9,7 +9,7 @@ Constructs a new instance of the `Field` class
Signature:
```typescript
-constructor(indexPattern: IIndexPattern, spec: FieldSpec | Field, shortDotsEnable: boolean, { fieldFormats, onNotification }: FieldDependencies);
+constructor(indexPattern: IIndexPattern, spec: FieldSpecExportFmt | FieldSpec | Field, shortDotsEnable: boolean, { fieldFormats, onNotification }: FieldDependencies);
```
## Parameters
@@ -17,7 +17,7 @@ constructor(indexPattern: IIndexPattern, spec: FieldSpec | Field, shortDotsEnabl
| Parameter | Type | Description |
| --- | --- | --- |
| indexPattern | IIndexPattern
| |
-| spec | FieldSpec | Field
| |
+| spec | FieldSpecExportFmt | FieldSpec | Field
| |
| shortDotsEnable | boolean
| |
| { fieldFormats, onNotification } | FieldDependencies
| |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md
index ca2552aeb1b425..ec19a4854bf0e6 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md
@@ -7,5 +7,5 @@
Signature:
```typescript
-conflictDescriptions?: Record;
+conflictDescriptions?: FieldSpecConflictDescriptions;
```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md
index 8fa1ee0d72e54d..d82999e7a96af4 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.md
@@ -22,7 +22,7 @@ export declare class Field implements IFieldType
| --- | --- | --- | --- |
| [$$spec](./kibana-plugin-plugins-data-public.indexpatternfield.__spec.md) | | FieldSpec
| |
| [aggregatable](./kibana-plugin-plugins-data-public.indexpatternfield.aggregatable.md) | | boolean
| |
-| [conflictDescriptions](./kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md) | | Record<string, string[]>
| |
+| [conflictDescriptions](./kibana-plugin-plugins-data-public.indexpatternfield.conflictdescriptions.md) | | FieldSpecConflictDescriptions
| |
| [count](./kibana-plugin-plugins-data-public.indexpatternfield.count.md) | | number
| |
| [displayName](./kibana-plugin-plugins-data-public.indexpatternfield.displayname.md) | | string
| |
| [esTypes](./kibana-plugin-plugins-data-public.indexpatternfield.estypes.md) | | string[]
| |
@@ -37,6 +37,7 @@ export declare class Field implements IFieldType
| [searchable](./kibana-plugin-plugins-data-public.indexpatternfield.searchable.md) | | boolean
| |
| [sortable](./kibana-plugin-plugins-data-public.indexpatternfield.sortable.md) | | boolean
| |
| [subType](./kibana-plugin-plugins-data-public.indexpatternfield.subtype.md) | | IFieldSubType
| |
+| [toSpec](./kibana-plugin-plugins-data-public.indexpatternfield.tospec.md) | | () => FieldSpecExportFmt
| |
| [type](./kibana-plugin-plugins-data-public.indexpatternfield.type.md) | | string
| |
| [visualizable](./kibana-plugin-plugins-data-public.indexpatternfield.visualizable.md) | | boolean
| |
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.tospec.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.tospec.md
new file mode 100644
index 00000000000000..35714faa03bc9a
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpatternfield.tospec.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPatternField](./kibana-plugin-plugins-data-public.indexpatternfield.md) > [toSpec](./kibana-plugin-plugins-data-public.indexpatternfield.tospec.md)
+
+## IndexPatternField.toSpec property
+
+Signature:
+
+```typescript
+toSpec: () => FieldSpecExportFmt;
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md
new file mode 100644
index 00000000000000..f1916e89c2c98e
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilter.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [isFilter](./kibana-plugin-plugins-data-public.isfilter.md)
+
+## isFilter variable
+
+Signature:
+
+```typescript
+isFilter: (x: unknown) => x is Filter
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md
new file mode 100644
index 00000000000000..558da72cc26bb4
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isfilters.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [isFilters](./kibana-plugin-plugins-data-public.isfilters.md)
+
+## isFilters variable
+
+Signature:
+
+```typescript
+isFilters: (x: unknown) => x is Filter[]
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isquery.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isquery.md
new file mode 100644
index 00000000000000..0884566333aa87
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.isquery.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [isQuery](./kibana-plugin-plugins-data-public.isquery.md)
+
+## isQuery variable
+
+Signature:
+
+```typescript
+isQuery: (x: unknown) => x is Query
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.istimerange.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.istimerange.md
new file mode 100644
index 00000000000000..e9420493c82fba
--- /dev/null
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.istimerange.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [isTimeRange](./kibana-plugin-plugins-data-public.istimerange.md)
+
+## isTimeRange variable
+
+Signature:
+
+```typescript
+isTimeRange: (x: unknown) => x is TimeRange
+```
diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
index f62479f02926e5..feeb686a1f5ede 100644
--- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
+++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md
@@ -110,6 +110,10 @@
| [getKbnTypeNames](./kibana-plugin-plugins-data-public.getkbntypenames.md) | Get the esTypes known by all kbnFieldTypes {Array} |
| [indexPatterns](./kibana-plugin-plugins-data-public.indexpatterns.md) | |
| [injectSearchSourceReferences](./kibana-plugin-plugins-data-public.injectsearchsourcereferences.md) | |
+| [isFilter](./kibana-plugin-plugins-data-public.isfilter.md) | |
+| [isFilters](./kibana-plugin-plugins-data-public.isfilters.md) | |
+| [isQuery](./kibana-plugin-plugins-data-public.isquery.md) | |
+| [isTimeRange](./kibana-plugin-plugins-data-public.istimerange.md) | |
| [parseSearchSourceJSON](./kibana-plugin-plugins-data-public.parsesearchsourcejson.md) | |
| [QueryStringInput](./kibana-plugin-plugins-data-public.querystringinput.md) | |
| [search](./kibana-plugin-plugins-data-public.search.md) | |
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.md
index 5375cf2a2ef431..77a2954428f8d4 100644
--- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.md
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.md
@@ -28,6 +28,7 @@ export interface IFieldType
| [searchable](./kibana-plugin-plugins-data-server.ifieldtype.searchable.md) | boolean
| |
| [sortable](./kibana-plugin-plugins-data-server.ifieldtype.sortable.md) | boolean
| |
| [subType](./kibana-plugin-plugins-data-server.ifieldtype.subtype.md) | IFieldSubType
| |
+| [toSpec](./kibana-plugin-plugins-data-server.ifieldtype.tospec.md) | () => FieldSpec
| |
| [type](./kibana-plugin-plugins-data-server.ifieldtype.type.md) | string
| |
| [visualizable](./kibana-plugin-plugins-data-server.ifieldtype.visualizable.md) | boolean
| |
diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.tospec.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.tospec.md
new file mode 100644
index 00000000000000..d1863bebce4f00
--- /dev/null
+++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ifieldtype.tospec.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [IFieldType](./kibana-plugin-plugins-data-server.ifieldtype.md) > [toSpec](./kibana-plugin-plugins-data-server.ifieldtype.tospec.md)
+
+## IFieldType.toSpec property
+
+Signature:
+
+```typescript
+toSpec?: () => FieldSpec;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/index.md b/docs/development/plugins/kibana_utils/common/state_containers/index.md
new file mode 100644
index 00000000000000..b4e1071ceb7324
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/index.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md)
+
+## API Reference
+
+## Packages
+
+| Package | Description |
+| --- | --- |
+| [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) | State containers are Redux-store-like objects meant to help you manage state in your services or apps. Refer to [guides and examples](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_containers) for more info |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestate.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestate.md
new file mode 100644
index 00000000000000..92893afc02beff
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestate.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [BaseState](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestate.md)
+
+## BaseState type
+
+Base [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) state shape
+
+Signature:
+
+```typescript
+export declare type BaseState = object;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.get.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.get.md
new file mode 100644
index 00000000000000..b939954d92aa6e
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.get.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md) > [get](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.get.md)
+
+## BaseStateContainer.get property
+
+Retrieves current state from the container
+
+Signature:
+
+```typescript
+get: () => State;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md
new file mode 100644
index 00000000000000..66c25c87f5e37d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md)
+
+## BaseStateContainer interface
+
+Base state container shape without transitions or selectors
+
+Signature:
+
+```typescript
+export interface BaseStateContainer
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [get](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.get.md) | () => State
| Retrieves current state from the container |
+| [set](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.set.md) | (state: State) => void
| Sets state into container |
+| [state$](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.state_.md) | Observable<State>
| of state |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.set.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.set.md
new file mode 100644
index 00000000000000..ed4ff365adfb35
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.set.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md) > [set](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.set.md)
+
+## BaseStateContainer.set property
+
+Sets state into container
+
+Signature:
+
+```typescript
+set: (state: State) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.state_.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.state_.md
new file mode 100644
index 00000000000000..35838fa53d5390
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.state_.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md) > [state$](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.state_.md)
+
+## BaseStateContainer.state$ property
+
+ of state
+
+Signature:
+
+```typescript
+state$: Observable;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.comparator.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.comparator.md
new file mode 100644
index 00000000000000..12af33756fb19d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.comparator.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Comparator](./kibana-plugin-plugins-kibana_utils-common-state_containers.comparator.md)
+
+## Comparator type
+
+Used to compare state. see [useContainerSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md)
+
+Signature:
+
+```typescript
+export declare type Comparator = (previous: Result, current: Result) => boolean;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md
new file mode 100644
index 00000000000000..e05f1fb392fe6e
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Connect](./kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md)
+
+## Connect type
+
+Similar to `connect` from react-redux, allows to map state from state container to component's props
+
+Signature:
+
+```typescript
+export declare type Connect = (mapStateToProp: MapStateToProps>) => (component: ComponentType) => FC>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer.md
new file mode 100644
index 00000000000000..cc43b59676dc13
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [createStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer.md)
+
+## createStateContainer() function
+
+Creates a state container without transitions and without selectors.
+
+Signature:
+
+```typescript
+export declare function createStateContainer(defaultState: State): ReduxLikeStateContainer;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| defaultState | State
| initial state |
+
+Returns:
+
+`ReduxLikeStateContainer`
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_1.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_1.md
new file mode 100644
index 00000000000000..794bf63588312f
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_1.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [createStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_1.md)
+
+## createStateContainer() function
+
+Creates a state container with transitions, but without selectors
+
+Signature:
+
+```typescript
+export declare function createStateContainer(defaultState: State, pureTransitions: PureTransitions): ReduxLikeStateContainer;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| defaultState | State
| initial state |
+| pureTransitions | PureTransitions
| state transitions configuration object. Map of . |
+
+Returns:
+
+`ReduxLikeStateContainer`
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_2.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_2.md
new file mode 100644
index 00000000000000..1946baae202f1d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_2.md
@@ -0,0 +1,27 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [createStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_2.md)
+
+## createStateContainer() function
+
+Creates a state container with transitions and selectors
+
+Signature:
+
+```typescript
+export declare function createStateContainer(defaultState: State, pureTransitions: PureTransitions, pureSelectors: PureSelectors, options?: CreateStateContainerOptions): ReduxLikeStateContainer;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| defaultState | State
| initial state |
+| pureTransitions | PureTransitions
| state transitions configuration object. Map of . |
+| pureSelectors | PureSelectors
| state selectors configuration object. Map of . |
+| options | CreateStateContainerOptions
| state container options [CreateStateContainerOptions](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md) |
+
+Returns:
+
+`ReduxLikeStateContainer`
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.freeze.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.freeze.md
new file mode 100644
index 00000000000000..4f772c7c54d084
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.freeze.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [CreateStateContainerOptions](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md) > [freeze](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.freeze.md)
+
+## CreateStateContainerOptions.freeze property
+
+Function to use when freezing state. Supply identity function. If not provided, default deepFreeze is use.
+
+Signature:
+
+```typescript
+freeze?: (state: T) => T;
+```
+
+## Example
+
+If you expect that your state will be mutated externally an you cannot prevent that
+
+```ts
+{
+ freeze: state => state,
+}
+
+```
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md
new file mode 100644
index 00000000000000..d328d306e93e1d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [CreateStateContainerOptions](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md)
+
+## CreateStateContainerOptions interface
+
+State container options
+
+Signature:
+
+```typescript
+export interface CreateStateContainerOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [freeze](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.freeze.md) | <T>(state: T) => T
| Function to use when freezing state. Supply identity function. If not provided, default deepFreeze is use. |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainerreacthelpers.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainerreacthelpers.md
new file mode 100644
index 00000000000000..a6076490c27465
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainerreacthelpers.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [createStateContainerReactHelpers](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainerreacthelpers.md)
+
+## createStateContainerReactHelpers variable
+
+Creates helpers for using [State Containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) with react Refer to [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_containers/react.md) for details
+
+Signature:
+
+```typescript
+createStateContainerReactHelpers: >() => {
+ Provider: React.Provider;
+ Consumer: React.Consumer;
+ context: React.Context;
+ useContainer: () => Container;
+ useState: () => UnboxState;
+ useTransitions: () => Container["transitions"];
+ useSelector: (selector: (state: UnboxState) => Result, comparator?: Comparator) => Result;
+ connect: Connect>;
+}
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.dispatch.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.dispatch.md
new file mode 100644
index 00000000000000..d4057a549bb0dc
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.dispatch.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Dispatch](./kibana-plugin-plugins-kibana_utils-common-state_containers.dispatch.md)
+
+## Dispatch type
+
+Redux like dispatch
+
+Signature:
+
+```typescript
+export declare type Dispatch = (action: T) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepureselector.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepureselector.md
new file mode 100644
index 00000000000000..5e4e86ad82d538
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepureselector.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [EnsurePureSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepureselector.md)
+
+## EnsurePureSelector type
+
+
+Signature:
+
+```typescript
+export declare type EnsurePureSelector = Ensure>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepuretransition.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepuretransition.md
new file mode 100644
index 00000000000000..0e621e989346b4
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepuretransition.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [EnsurePureTransition](./kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepuretransition.md)
+
+## EnsurePureTransition type
+
+
+Signature:
+
+```typescript
+export declare type EnsurePureTransition = Ensure>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.mapstatetoprops.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.mapstatetoprops.md
new file mode 100644
index 00000000000000..8e6a49ac727426
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.mapstatetoprops.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [MapStateToProps](./kibana-plugin-plugins-kibana_utils-common-state_containers.mapstatetoprops.md)
+
+## MapStateToProps type
+
+State container state to component props mapper. See [Connect](./kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md)
+
+Signature:
+
+```typescript
+export declare type MapStateToProps = (state: State) => StateProps;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.md
new file mode 100644
index 00000000000000..e74ff2c6885be1
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.md
@@ -0,0 +1,52 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md)
+
+## kibana-plugin-plugins-kibana\_utils-common-state\_containers package
+
+State containers are Redux-store-like objects meant to help you manage state in your services or apps. Refer to [guides and examples](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_containers) for more info
+
+## Functions
+
+| Function | Description |
+| --- | --- |
+| [createStateContainer(defaultState)](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer.md) | Creates a state container without transitions and without selectors. |
+| [createStateContainer(defaultState, pureTransitions)](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_1.md) | Creates a state container with transitions, but without selectors |
+| [createStateContainer(defaultState, pureTransitions, pureSelectors, options)](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainer_2.md) | Creates a state container with transitions and selectors |
+
+## Interfaces
+
+| Interface | Description |
+| --- | --- |
+| [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md) | Base state container shape without transitions or selectors |
+| [CreateStateContainerOptions](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontaineroptions.md) | State container options |
+| [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) | Fully featured state container which matches Redux store interface. Extends [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) Allows to use state container with redux libraries |
+| [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) | Fully featured state container with [Selectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md) and . Extends [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md) |
+
+## Variables
+
+| Variable | Description |
+| --- | --- |
+| [createStateContainerReactHelpers](./kibana-plugin-plugins-kibana_utils-common-state_containers.createstatecontainerreacthelpers.md) | Creates helpers for using [State Containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) with react Refer to [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_containers/react.md) for details |
+| [useContainerSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md) | React hook to apply selector to state container to extract only needed information. Will re-render your component only when the section changes. |
+| [useContainerState](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerstate.md) | React hooks that returns the latest state of a [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md). |
+
+## Type Aliases
+
+| Type Alias | Description |
+| --- | --- |
+| [BaseState](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestate.md) | Base [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) state shape |
+| [Comparator](./kibana-plugin-plugins-kibana_utils-common-state_containers.comparator.md) | Used to compare state. see [useContainerSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md) |
+| [Connect](./kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md) | Similar to connect
from react-redux, allows to map state from state container to component's props |
+| [Dispatch](./kibana-plugin-plugins-kibana_utils-common-state_containers.dispatch.md) | Redux like dispatch |
+| [EnsurePureSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepureselector.md) | |
+| [EnsurePureTransition](./kibana-plugin-plugins-kibana_utils-common-state_containers.ensurepuretransition.md) | |
+| [MapStateToProps](./kibana-plugin-plugins-kibana_utils-common-state_containers.mapstatetoprops.md) | State container state to component props mapper. See [Connect](./kibana-plugin-plugins-kibana_utils-common-state_containers.connect.md) |
+| [Middleware](./kibana-plugin-plugins-kibana_utils-common-state_containers.middleware.md) | Redux like Middleware |
+| [PureSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselector.md) | |
+| [PureSelectorsToSelectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectorstoselectors.md) | |
+| [PureSelectorToSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectortoselector.md) | |
+| [Reducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reducer.md) | Redux like Reducer |
+| [Selector](./kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md) | |
+| [UnboxState](./kibana-plugin-plugins-kibana_utils-common-state_containers.unboxstate.md) | Utility type for inferring state shape from [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.middleware.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.middleware.md
new file mode 100644
index 00000000000000..574b83306dc959
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.middleware.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Middleware](./kibana-plugin-plugins-kibana_utils-common-state_containers.middleware.md)
+
+## Middleware type
+
+Redux like Middleware
+
+Signature:
+
+```typescript
+export declare type Middleware = (store: Pick, 'getState' | 'dispatch'>) => (next: (action: TransitionDescription) => TransitionDescription | any) => Dispatch;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselector.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselector.md
new file mode 100644
index 00000000000000..6ac07cba446f51
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselector.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [PureSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselector.md)
+
+## PureSelector type
+
+
+Signature:
+
+```typescript
+export declare type PureSelector = (state: State) => Selector;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectorstoselectors.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectorstoselectors.md
new file mode 100644
index 00000000000000..82a91f7c87e17f
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectorstoselectors.md
@@ -0,0 +1,14 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [PureSelectorsToSelectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectorstoselectors.md)
+
+## PureSelectorsToSelectors type
+
+
+Signature:
+
+```typescript
+export declare type PureSelectorsToSelectors = {
+ [K in keyof T]: PureSelectorToSelector>;
+};
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectortoselector.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectortoselector.md
new file mode 100644
index 00000000000000..5c12afd1cd971a
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectortoselector.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [PureSelectorToSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.pureselectortoselector.md)
+
+## PureSelectorToSelector type
+
+
+Signature:
+
+```typescript
+export declare type PureSelectorToSelector> = ReturnType>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reducer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reducer.md
new file mode 100644
index 00000000000000..519e6ce7d7cfb3
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reducer.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Reducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reducer.md)
+
+## Reducer type
+
+Redux like Reducer
+
+Signature:
+
+```typescript
+export declare type Reducer = (state: State, action: TransitionDescription) => State;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.addmiddleware.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.addmiddleware.md
new file mode 100644
index 00000000000000..e90da05e30d878
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.addmiddleware.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [addMiddleware](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.addmiddleware.md)
+
+## ReduxLikeStateContainer.addMiddleware property
+
+Signature:
+
+```typescript
+addMiddleware: (middleware: Middleware) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.dispatch.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.dispatch.md
new file mode 100644
index 00000000000000..7a9755ee3b65cd
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.dispatch.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [dispatch](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.dispatch.md)
+
+## ReduxLikeStateContainer.dispatch property
+
+Signature:
+
+```typescript
+dispatch: (action: TransitionDescription) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.getstate.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.getstate.md
new file mode 100644
index 00000000000000..86e1c6dd34cd6a
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.getstate.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [getState](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.getstate.md)
+
+## ReduxLikeStateContainer.getState property
+
+Signature:
+
+```typescript
+getState: () => State;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md
new file mode 100644
index 00000000000000..0e08119c1eae44
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md)
+
+## ReduxLikeStateContainer interface
+
+Fully featured state container which matches Redux store interface. Extends [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) Allows to use state container with redux libraries
+
+Signature:
+
+```typescript
+export interface ReduxLikeStateContainer extends StateContainer
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [addMiddleware](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.addmiddleware.md) | (middleware: Middleware<State>) => void
| |
+| [dispatch](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.dispatch.md) | (action: TransitionDescription) => void
| |
+| [getState](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.getstate.md) | () => State
| |
+| [reducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.reducer.md) | Reducer<State>
| |
+| [replaceReducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.replacereducer.md) | (nextReducer: Reducer<State>) => void
| |
+| [subscribe](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.subscribe.md) | (listener: (state: State) => void) => () => void
| |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.reducer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.reducer.md
new file mode 100644
index 00000000000000..49eabf19340f2b
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.reducer.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [reducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.reducer.md)
+
+## ReduxLikeStateContainer.reducer property
+
+Signature:
+
+```typescript
+reducer: Reducer;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.replacereducer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.replacereducer.md
new file mode 100644
index 00000000000000..2582d31d9adc4f
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.replacereducer.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [replaceReducer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.replacereducer.md)
+
+## ReduxLikeStateContainer.replaceReducer property
+
+Signature:
+
+```typescript
+replaceReducer: (nextReducer: Reducer) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.subscribe.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.subscribe.md
new file mode 100644
index 00000000000000..15139a7bd9f3e6
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.subscribe.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [ReduxLikeStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.md) > [subscribe](./kibana-plugin-plugins-kibana_utils-common-state_containers.reduxlikestatecontainer.subscribe.md)
+
+## ReduxLikeStateContainer.subscribe property
+
+Signature:
+
+```typescript
+subscribe: (listener: (state: State) => void) => () => void;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md
new file mode 100644
index 00000000000000..5c143551d130b3
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [Selector](./kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md)
+
+## Selector type
+
+
+Signature:
+
+```typescript
+export declare type Selector = (...args: Args) => Result;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md
new file mode 100644
index 00000000000000..23ec1c8e5be010
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md)
+
+## StateContainer interface
+
+Fully featured state container with [Selectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.selector.md) and . Extends [BaseStateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.basestatecontainer.md)
+
+Signature:
+
+```typescript
+export interface StateContainer extends BaseStateContainer
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [selectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.selectors.md) | Readonly<PureSelectorsToSelectors<PureSelectors>>
| |
+| [transitions](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.transitions.md) | Readonly<PureTransitionsToTransitions<PureTransitions>>
| |
+
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.selectors.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.selectors.md
new file mode 100644
index 00000000000000..2afac07b59e396
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.selectors.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) > [selectors](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.selectors.md)
+
+## StateContainer.selectors property
+
+Signature:
+
+```typescript
+selectors: Readonly>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.transitions.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.transitions.md
new file mode 100644
index 00000000000000..4712d3287beef5
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.transitions.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md) > [transitions](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.transitions.md)
+
+## StateContainer.transitions property
+
+Signature:
+
+```typescript
+transitions: Readonly>;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.unboxstate.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.unboxstate.md
new file mode 100644
index 00000000000000..d4f99841456d74
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.unboxstate.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [UnboxState](./kibana-plugin-plugins-kibana_utils-common-state_containers.unboxstate.md)
+
+## UnboxState type
+
+Utility type for inferring state shape from [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md)
+
+Signature:
+
+```typescript
+export declare type UnboxState> = Container extends StateContainer ? T : never;
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md
new file mode 100644
index 00000000000000..fe5f30a9c84720
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [useContainerSelector](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerselector.md)
+
+## useContainerSelector variable
+
+React hook to apply selector to state container to extract only needed information. Will re-render your component only when the section changes.
+
+Signature:
+
+```typescript
+useContainerSelector: , Result>(container: Container, selector: (state: UnboxState) => Result, comparator?: Comparator) => Result
+```
diff --git a/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerstate.md b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerstate.md
new file mode 100644
index 00000000000000..7cef47c58f9d98
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/common/state_containers/kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerstate.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-common-state\_containers](./kibana-plugin-plugins-kibana_utils-common-state_containers.md) > [useContainerState](./kibana-plugin-plugins-kibana_utils-common-state_containers.usecontainerstate.md)
+
+## useContainerState variable
+
+React hooks that returns the latest state of a [StateContainer](./kibana-plugin-plugins-kibana_utils-common-state_containers.statecontainer.md).
+
+Signature:
+
+```typescript
+useContainerState: >(container: Container) => UnboxState
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/index.md b/docs/development/plugins/kibana_utils/public/state_sync/index.md
new file mode 100644
index 00000000000000..4b345d9130bd54
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/index.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md)
+
+## API Reference
+
+## Packages
+
+| Package | Description |
+| --- | --- |
+| [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) | State syncing utilities are a set of helpers for syncing your application state with URL or browser storage.They are designed to work together with state containers (). But state containers are not required.State syncing utilities include:- util which: - Subscribes to state changes and pushes them to state storage. - Optionally subscribes to state storage changes and pushes them to state. - Two types of storage compatible with syncState
: - - Serializes state and persists it to URL's query param in rison or hashed format. Listens for state updates in the URL and pushes them back to state. - - Serializes state and persists it to browser storage.Refer [here](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_sync) for a complete guide and examples |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createkbnurlstatestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createkbnurlstatestorage.md
new file mode 100644
index 00000000000000..22f70ce22b5745
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createkbnurlstatestorage.md
@@ -0,0 +1,16 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [createKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.createkbnurlstatestorage.md)
+
+## createKbnUrlStateStorage variable
+
+Creates [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) state storage
+
+Signature:
+
+```typescript
+createKbnUrlStateStorage: ({ useHash, history }?: {
+ useHash: boolean;
+ history?: History | undefined;
+}) => IKbnUrlStateStorage
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createsessionstoragestatestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createsessionstoragestatestorage.md
new file mode 100644
index 00000000000000..dccff93ad17247
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.createsessionstoragestatestorage.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [createSessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.createsessionstoragestatestorage.md)
+
+## createSessionStorageStateStorage variable
+
+Creates [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/session_storage.md)
+
+Signature:
+
+```typescript
+createSessionStorageStateStorage: (storage?: Storage) => ISessionStorageStateStorage
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.cancel.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.cancel.md
new file mode 100644
index 00000000000000..29a511d57d7bd6
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.cancel.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) > [cancel](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.cancel.md)
+
+## IKbnUrlStateStorage.cancel property
+
+cancels any pending url updates
+
+Signature:
+
+```typescript
+cancel: () => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.change_.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.change_.md
new file mode 100644
index 00000000000000..2b55f2aca70c81
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.change_.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) > [change$](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.change_.md)
+
+## IKbnUrlStateStorage.change$ property
+
+Signature:
+
+```typescript
+change$: (key: string) => Observable;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.flush.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.flush.md
new file mode 100644
index 00000000000000..e0e6aa9be4368b
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.flush.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) > [flush](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.flush.md)
+
+## IKbnUrlStateStorage.flush property
+
+synchronously runs any pending url updates returned boolean indicates if change occurred
+
+Signature:
+
+```typescript
+flush: (opts?: {
+ replace?: boolean;
+ }) => boolean;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.get.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.get.md
new file mode 100644
index 00000000000000..0eb60c21fbbbfc
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.get.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) > [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.get.md)
+
+## IKbnUrlStateStorage.get property
+
+Signature:
+
+```typescript
+get: (key: string) => State | null;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md
new file mode 100644
index 00000000000000..56cefebd2acfe6
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md)
+
+## IKbnUrlStateStorage interface
+
+KbnUrlStateStorage is a state storage for [syncState()](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md) utility which: 1. Keeps state in sync with the URL. 2. Serializes data and stores it in the URL in one of the supported formats: \* Rison encoded. \* Hashed URL: In URL we store only the hash from the serialized state, but the state itself is stored in sessionStorage. See kibana's advanced option for more context state:storeInSessionStorage 3. Takes care of listening to the URL updates and notifies state about the updates. 4. Takes care of batching URL updates to prevent redundant browser history records. [GUIDE](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/kbn_url_storage.md)
+
+Signature:
+
+```typescript
+export interface IKbnUrlStateStorage extends IStateStorage
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [cancel](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.cancel.md) | () => void
| cancels any pending url updates |
+| [change$](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.change_.md) | <State = unknown>(key: string) => Observable<State | null>
| |
+| [flush](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.flush.md) | (opts?: {
replace?: boolean;
}) => boolean
| synchronously runs any pending url updates returned boolean indicates if change occurred |
+| [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.get.md) | <State = unknown>(key: string) => State | null
| |
+| [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.set.md) | <State>(key: string, state: State, opts?: {
replace: boolean;
}) => Promise<string | undefined>
| |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.set.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.set.md
new file mode 100644
index 00000000000000..2eab44d3444144
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.set.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) > [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.set.md)
+
+## IKbnUrlStateStorage.set property
+
+Signature:
+
+```typescript
+set: (key: string, state: State, opts?: {
+ replace: boolean;
+ }) => Promise;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md
new file mode 100644
index 00000000000000..ca69609936405c
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md
@@ -0,0 +1,24 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [INullableBaseStateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md)
+
+## INullableBaseStateContainer interface
+
+Extension of with one constraint: set state should handle `null` as incoming state
+
+Signature:
+
+```typescript
+export interface INullableBaseStateContainer extends BaseStateContainer
+```
+
+## Remarks
+
+State container for stateSync() have to accept "null" for example, set() implementation could handle null and fallback to some default state this is required to handle edge case, when state in storage becomes empty and syncing is in progress. state container will be notified about about storage becoming empty with null passed in
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.set.md) | (state: State | null) => void
| |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.set.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.set.md
new file mode 100644
index 00000000000000..dd2978f59484a0
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.set.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [INullableBaseStateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md) > [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.set.md)
+
+## INullableBaseStateContainer.set property
+
+Signature:
+
+```typescript
+set: (state: State | null) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.get.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.get.md
new file mode 100644
index 00000000000000..83131c77132cee
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.get.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) > [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.get.md)
+
+## ISessionStorageStateStorage.get property
+
+Signature:
+
+```typescript
+get: (key: string) => State | null;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md
new file mode 100644
index 00000000000000..7792bc3932f956
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md
@@ -0,0 +1,21 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md)
+
+## ISessionStorageStateStorage interface
+
+[IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) for storing state in browser [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/session_storage.md)
+
+Signature:
+
+```typescript
+export interface ISessionStorageStateStorage extends IStateStorage
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.get.md) | <State = unknown>(key: string) => State | null
| |
+| [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.set.md) | <State>(key: string, state: State) => void
| |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.set.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.set.md
new file mode 100644
index 00000000000000..04b0ab01f0d133
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.set.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) > [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.set.md)
+
+## ISessionStorageStateStorage.set property
+
+Signature:
+
+```typescript
+set: (key: string, state: State) => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.cancel.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.cancel.md
new file mode 100644
index 00000000000000..ce771d52a6e60f
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.cancel.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) > [cancel](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.cancel.md)
+
+## IStateStorage.cancel property
+
+Optional method to cancel any pending activity syncState() will call it, if it is provided by IStateStorage
+
+Signature:
+
+```typescript
+cancel?: () => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.change_.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.change_.md
new file mode 100644
index 00000000000000..ed6672a3d83c62
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.change_.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) > [change$](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.change_.md)
+
+## IStateStorage.change$ property
+
+Should notify when the stored state has changed
+
+Signature:
+
+```typescript
+change$?: (key: string) => Observable;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.get.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.get.md
new file mode 100644
index 00000000000000..2c0b2ee970cc62
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.get.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) > [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.get.md)
+
+## IStateStorage.get property
+
+Should retrieve state from the storage and deserialize it
+
+Signature:
+
+```typescript
+get: (key: string) => State | null;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md
new file mode 100644
index 00000000000000..2c34a185fb7b12
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md
@@ -0,0 +1,25 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md)
+
+## IStateStorage interface
+
+Any StateStorage have to implement IStateStorage interface StateStorage is responsible for: \* state serialisation / deserialization \* persisting to and retrieving from storage
+
+For an example take a look at already implemented [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) and [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) state storages
+
+Signature:
+
+```typescript
+export interface IStateStorage
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [cancel](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.cancel.md) | () => void
| Optional method to cancel any pending activity syncState() will call it, if it is provided by IStateStorage |
+| [change$](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.change_.md) | <State = unknown>(key: string) => Observable<State | null>
| Should notify when the stored state has changed |
+| [get](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.get.md) | <State = unknown>(key: string) => State | null
| Should retrieve state from the storage and deserialize it |
+| [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.set.md) | <State>(key: string, state: State) => any
| Take in a state object, should serialise and persist |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.set.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.set.md
new file mode 100644
index 00000000000000..3f286994ed4afc
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.set.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) > [set](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.set.md)
+
+## IStateStorage.set property
+
+Take in a state object, should serialise and persist
+
+Signature:
+
+```typescript
+set: (key: string, state: State) => any;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md
new file mode 100644
index 00000000000000..f9368de4240ac6
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md
@@ -0,0 +1,22 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md)
+
+## IStateSyncConfig interface
+
+Config for setting up state syncing with
+
+Signature:
+
+```typescript
+export interface IStateSyncConfig
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [stateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statecontainer.md) | INullableBaseStateContainer<State>
| State container to keep in sync with storage, have to implement [INullableBaseStateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md) interface We encourage to use as a state container, but it is also possible to implement own custom container for advanced use cases |
+| [stateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statestorage.md) | StateStorage
| State storage to use, State storage is responsible for serialising / deserialising and persisting / retrieving stored stateThere are common strategies already implemented: see [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) which replicate what State (AppState, GlobalState) in legacy world did |
+| [storageKey](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.storagekey.md) | string
| Storage key to use for syncing, e.g. storageKey '\_a' should sync state to ?\_a query param |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statecontainer.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statecontainer.md
new file mode 100644
index 00000000000000..0098dd5c99aeb3
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statecontainer.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md) > [stateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statecontainer.md)
+
+## IStateSyncConfig.stateContainer property
+
+State container to keep in sync with storage, have to implement [INullableBaseStateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md) interface We encourage to use as a state container, but it is also possible to implement own custom container for advanced use cases
+
+Signature:
+
+```typescript
+stateContainer: INullableBaseStateContainer;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statestorage.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statestorage.md
new file mode 100644
index 00000000000000..ef872ba0ba9b5d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statestorage.md
@@ -0,0 +1,15 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md) > [stateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.statestorage.md)
+
+## IStateSyncConfig.stateStorage property
+
+State storage to use, State storage is responsible for serialising / deserialising and persisting / retrieving stored state
+
+There are common strategies already implemented: see [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) which replicate what State (AppState, GlobalState) in legacy world did
+
+Signature:
+
+```typescript
+stateStorage: StateStorage;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.storagekey.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.storagekey.md
new file mode 100644
index 00000000000000..d3887c23df1e0d
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.storagekey.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md) > [storageKey](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.storagekey.md)
+
+## IStateSyncConfig.storageKey property
+
+Storage key to use for syncing, e.g. storageKey '\_a' should sync state to ?\_a query param
+
+Signature:
+
+```typescript
+storageKey: string;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md
new file mode 100644
index 00000000000000..137db68cd6b487
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md
@@ -0,0 +1,20 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISyncStateRef](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md)
+
+## ISyncStateRef interface
+
+
+Signature:
+
+```typescript
+export interface ISyncStateRef
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [start](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.start.md) | StartSyncStateFnType
| start state syncing |
+| [stop](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.stop.md) | StopSyncStateFnType
| stop state syncing |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.start.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.start.md
new file mode 100644
index 00000000000000..d8df808ba215f4
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.start.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISyncStateRef](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md) > [start](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.start.md)
+
+## ISyncStateRef.start property
+
+start state syncing
+
+Signature:
+
+```typescript
+start: StartSyncStateFnType;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.stop.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.stop.md
new file mode 100644
index 00000000000000..70356dd9d6c791
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.stop.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [ISyncStateRef](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md) > [stop](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.stop.md)
+
+## ISyncStateRef.stop property
+
+stop state syncing
+
+Signature:
+
+```typescript
+stop: StopSyncStateFnType;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.md
new file mode 100644
index 00000000000000..2b02c98e0d6053
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.md
@@ -0,0 +1,48 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md)
+
+## kibana-plugin-plugins-kibana\_utils-public-state\_sync package
+
+State syncing utilities are a set of helpers for syncing your application state with URL or browser storage.
+
+They are designed to work together with state containers (). But state containers are not required.
+
+State syncing utilities include:
+
+- [syncState()](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md) util which: - Subscribes to state changes and pushes them to state storage. - Optionally subscribes to state storage changes and pushes them to state. - Two types of storage compatible with `syncState`: - [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) - Serializes state and persists it to URL's query param in rison or hashed format. Listens for state updates in the URL and pushes them back to state. - [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) - Serializes state and persists it to browser storage.
+
+Refer [here](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_sync) for a complete guide and examples
+
+## Functions
+
+| Function | Description |
+| --- | --- |
+| [syncState({ storageKey, stateStorage, stateContainer, })](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md) | Utility for syncing application state wrapped in state container with some kind of storage (e.g. URL) Refer [here](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_sync) for a complete guide and examples |
+| [syncStates(stateSyncConfigs)](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstates.md) | |
+
+## Interfaces
+
+| Interface | Description |
+| --- | --- |
+| [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) | KbnUrlStateStorage is a state storage for [syncState()](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md) utility which: 1. Keeps state in sync with the URL. 2. Serializes data and stores it in the URL in one of the supported formats: \* Rison encoded. \* Hashed URL: In URL we store only the hash from the serialized state, but the state itself is stored in sessionStorage. See kibana's advanced option for more context state:storeInSessionStorage 3. Takes care of listening to the URL updates and notifies state about the updates. 4. Takes care of batching URL updates to prevent redundant browser history records. [GUIDE](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/kbn_url_storage.md) |
+| [INullableBaseStateContainer](./kibana-plugin-plugins-kibana_utils-public-state_sync.inullablebasestatecontainer.md) | Extension of with one constraint: set state should handle null
as incoming state |
+| [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) | [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) for storing state in browser [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/session_storage.md) |
+| [IStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatestorage.md) | Any StateStorage have to implement IStateStorage interface StateStorage is responsible for: \* state serialisation / deserialization \* persisting to and retrieving from storageFor an example take a look at already implemented [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) and [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) state storages |
+| [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md) | Config for setting up state syncing with |
+| [ISyncStateRef](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md) | |
+
+## Variables
+
+| Variable | Description |
+| --- | --- |
+| [createKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.createkbnurlstatestorage.md) | Creates [IKbnUrlStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.ikbnurlstatestorage.md) state storage |
+| [createSessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.createsessionstoragestatestorage.md) | Creates [ISessionStorageStateStorage](./kibana-plugin-plugins-kibana_utils-public-state_sync.isessionstoragestatestorage.md) [guide](https://github.com/elastic/kibana/blob/master/src/plugins/kibana_utils/docs/state_sync/storages/session_storage.md) |
+
+## Type Aliases
+
+| Type Alias | Description |
+| --- | --- |
+| [StartSyncStateFnType](./kibana-plugin-plugins-kibana_utils-public-state_sync.startsyncstatefntype.md) | |
+| [StopSyncStateFnType](./kibana-plugin-plugins-kibana_utils-public-state_sync.stopsyncstatefntype.md) | |
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.startsyncstatefntype.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.startsyncstatefntype.md
new file mode 100644
index 00000000000000..23f71ba330d4b9
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.startsyncstatefntype.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [StartSyncStateFnType](./kibana-plugin-plugins-kibana_utils-public-state_sync.startsyncstatefntype.md)
+
+## StartSyncStateFnType type
+
+
+Signature:
+
+```typescript
+export declare type StartSyncStateFnType = () => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.stopsyncstatefntype.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.stopsyncstatefntype.md
new file mode 100644
index 00000000000000..69ff6e899e8604
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.stopsyncstatefntype.md
@@ -0,0 +1,12 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [StopSyncStateFnType](./kibana-plugin-plugins-kibana_utils-public-state_sync.stopsyncstatefntype.md)
+
+## StopSyncStateFnType type
+
+
+Signature:
+
+```typescript
+export declare type StopSyncStateFnType = () => void;
+```
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md
new file mode 100644
index 00000000000000..d095c3fffc512a
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md
@@ -0,0 +1,93 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [syncState](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstate.md)
+
+## syncState() function
+
+Utility for syncing application state wrapped in state container with some kind of storage (e.g. URL) Refer [here](https://github.com/elastic/kibana/tree/master/src/plugins/kibana_utils/docs/state_sync) for a complete guide and examples
+
+Signature:
+
+```typescript
+export declare function syncState({ storageKey, stateStorage, stateContainer, }: IStateSyncConfig): ISyncStateRef;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| { storageKey, stateStorage, stateContainer, } | IStateSyncConfig<State, IStateStorage>
| |
+
+Returns:
+
+`ISyncStateRef`
+
+- [ISyncStateRef](./kibana-plugin-plugins-kibana_utils-public-state_sync.isyncstateref.md)
+
+## Remarks
+
+1. It is responsibility of consumer to make sure that initial app state and storage are in sync before starting syncing No initial sync happens when syncState() is called
+
+## Example 1
+
+1. the simplest use case
+
+```ts
+const stateStorage = createKbnUrlStateStorage();
+syncState({
+ storageKey: '_s',
+ stateContainer,
+ stateStorage
+});
+
+```
+
+## Example 2
+
+2. conditionally configuring sync strategy
+
+```ts
+const stateStorage = createKbnUrlStateStorage({useHash: config.get('state:stateContainerInSessionStorage')})
+syncState({
+ storageKey: '_s',
+ stateContainer,
+ stateStorage
+});
+
+```
+
+## Example 3
+
+3. implementing custom sync strategy
+
+```ts
+const localStorageStateStorage = {
+ set: (storageKey, state) => localStorage.setItem(storageKey, JSON.stringify(state)),
+ get: (storageKey) => localStorage.getItem(storageKey) ? JSON.parse(localStorage.getItem(storageKey)) : null
+};
+syncState({
+ storageKey: '_s',
+ stateContainer,
+ stateStorage: localStorageStateStorage
+});
+
+```
+
+## Example 4
+
+4. Transform state before serialising Useful for: \* Migration / backward compatibility \* Syncing part of state \* Providing default values
+
+```ts
+const stateToStorage = (s) => ({ tab: s.tab });
+syncState({
+ storageKey: '_s',
+ stateContainer: {
+ get: () => stateToStorage(stateContainer.get()),
+ set: stateContainer.set(({ tab }) => ({ ...stateContainer.get(), tab }),
+ state$: stateContainer.state$.pipe(map(stateToStorage))
+ },
+ stateStorage
+});
+
+```
+
diff --git a/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstates.md b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstates.md
new file mode 100644
index 00000000000000..87a2449a384df5
--- /dev/null
+++ b/docs/development/plugins/kibana_utils/public/state_sync/kibana-plugin-plugins-kibana_utils-public-state_sync.syncstates.md
@@ -0,0 +1,42 @@
+
+
+[Home](./index.md) > [kibana-plugin-plugins-kibana\_utils-public-state\_sync](./kibana-plugin-plugins-kibana_utils-public-state_sync.md) > [syncStates](./kibana-plugin-plugins-kibana_utils-public-state_sync.syncstates.md)
+
+## syncStates() function
+
+Signature:
+
+```typescript
+export declare function syncStates(stateSyncConfigs: Array>): ISyncStateRef;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| stateSyncConfigs | Array<IStateSyncConfig<any>>
| Array of [IStateSyncConfig](./kibana-plugin-plugins-kibana_utils-public-state_sync.istatesyncconfig.md) to sync |
+
+Returns:
+
+`ISyncStateRef`
+
+## Example
+
+sync multiple different sync configs
+
+```ts
+syncStates([
+ {
+ storageKey: '_s1',
+ stateStorage: stateStorage1,
+ stateContainer: stateContainer1,
+ },
+ {
+ storageKey: '_s2',
+ stateStorage: stateStorage2,
+ stateContainer: stateContainer2,
+ },
+]);
+
+```
+
diff --git a/docs/images/data-viz-homepage.jpg b/docs/images/data-viz-homepage.jpg
new file mode 100644
index 00000000000000..f7a952b65d41f4
Binary files /dev/null and b/docs/images/data-viz-homepage.jpg differ
diff --git a/docs/setup/connect-to-elasticsearch.asciidoc b/docs/setup/connect-to-elasticsearch.asciidoc
index 8c04167de12361..bffb3f97cd1b9c 100644
--- a/docs/setup/connect-to-elasticsearch.asciidoc
+++ b/docs/setup/connect-to-elasticsearch.asciidoc
@@ -18,10 +18,16 @@ to see all that you can do in {kib}.
[[upload-data-kibana]]
=== Upload a CSV, JSON, or log file
-To visualize data in a CSV, JSON, or log file, you can
-upload it using the File Data Visualizer. On the home page,
-click *Import a CSV, NDSON, or log file*, and then drag your file into the
-File Data Visualizer.
+experimental[]
+
+To visualize data in a CSV, JSON, or log file, you can upload it using the File
+Data Visualizer. On the home page, click *Import a CSV, NDSON, or log file*, and
+then drag your file into the File Data Visualizer. Alternatively, you can open
+it by navigating to *Machine Learning* from the side navigation and selecting
+*Data Visualizer*.
+
+[role="screenshot"]
+image::images/data-viz-homepage.jpg[File Data Visualizer on the home page]
You can upload a file up to 100 MB. This value is configurable up to 1 GB in
<>.
diff --git a/package.json b/package.json
index 3eaa1fb05e906e..b1202631a0c026 100644
--- a/package.json
+++ b/package.json
@@ -139,6 +139,7 @@
"@kbn/babel-preset": "1.0.0",
"@kbn/config-schema": "1.0.0",
"@kbn/i18n": "1.0.0",
+ "@kbn/telemetry-tools": "1.0.0",
"@kbn/interpreter": "1.0.0",
"@kbn/pm": "1.0.0",
"@kbn/test-subj-selector": "0.2.1",
@@ -406,7 +407,7 @@
"babel-eslint": "^10.0.3",
"babel-jest": "^25.5.1",
"babel-plugin-istanbul": "^6.0.0",
- "backport": "5.4.1",
+ "backport": "5.4.6",
"chai": "3.5.0",
"chance": "1.0.18",
"cheerio": "0.22.0",
diff --git a/packages/kbn-monaco/src/xjson/grammar.ts b/packages/kbn-monaco/src/xjson/grammar.ts
index e95059f9ece2dd..fbd7b3d319c1de 100644
--- a/packages/kbn-monaco/src/xjson/grammar.ts
+++ b/packages/kbn-monaco/src/xjson/grammar.ts
@@ -200,12 +200,13 @@ export const createParser = () => {
try {
value();
+ white();
} catch (e) {
errored = true;
annos.push({ type: AnnoTypes.error, at: e.at - 1, text: e.message });
}
if (!errored && ch) {
- error('Syntax error');
+ annos.push({ type: AnnoTypes.error, at: at, text: 'Syntax Error' });
}
return { annotations: annos };
}
diff --git a/packages/kbn-monaco/src/xjson/language.ts b/packages/kbn-monaco/src/xjson/language.ts
index fe505818d3c9ab..54b7004fecd8e5 100644
--- a/packages/kbn-monaco/src/xjson/language.ts
+++ b/packages/kbn-monaco/src/xjson/language.ts
@@ -52,7 +52,10 @@ export const registerGrammarChecker = (editor: monaco.editor.IEditor) => {
const updateAnnos = async () => {
const { annotations } = await wps.getAnnos();
- const model = editor.getModel() as monaco.editor.ITextModel;
+ const model = editor.getModel() as monaco.editor.ITextModel | null;
+ if (!model) {
+ return;
+ }
monaco.editor.setModelMarkers(
model,
OWNER,
diff --git a/packages/kbn-telemetry-tools/README.md b/packages/kbn-telemetry-tools/README.md
new file mode 100644
index 00000000000000..ccd092c76a17c4
--- /dev/null
+++ b/packages/kbn-telemetry-tools/README.md
@@ -0,0 +1,89 @@
+# Telemetry Tools
+
+## Schema extraction tool
+
+### Description
+
+The tool is used to extract telemetry collectors schema from all `*.{ts}` files in provided plugins directories to JSON files. The tool looks for `.telemetryrc.json` files in the root of the project and in the `x-pack` dir for its runtime configurations.
+
+It uses typescript parser to build an AST for each file. The tool is able to validate, extract and match collector schemas.
+
+### Examples and restrictions
+
+**Global restrictions**:
+
+The `id` can be only a string literal, it cannot be a template literals w/o expressions or string-only concatenation expressions or anything else.
+
+```
+export const myCollector = makeUsageCollector({
+ type: 'string_literal_only',
+ ...
+});
+```
+
+### Usage
+
+```bash
+node scripts/telemetry_extract.js
+```
+
+This command has no additional flags or arguments. The `.telemetryrc.json` files specify the path to the directory where searching should start, output json files, and files to exclude.
+
+
+### Output
+
+
+The generated JSON files contain an ES mapping for each schema. This mapping is used to verify changes in the collectors and as the basis to map those fields into the external telemetry cluster.
+
+**Example**:
+
+```json
+{
+ "properties": {
+ "cloud": {
+ "properties": {
+ "isCloudEnabled": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+}
+```
+
+## Schema validation tool
+
+### Description
+
+The tool performs a number of checks on all telemetry collectors and verifies the following:
+
+1. Verifies the collector structure, fields, and returned values are using the appropriate types.
+2. Verifies that the collector `fetch` function Type matches the specified `schema` in the collector.
+3. Verifies that the collector `schema` matches the stored json schema .
+
+### Notes
+
+We don't catch every possible misuse of the collectors, but only the most common and critical ones.
+
+What will not be caught by the validator:
+
+* Mistyped SavedObject/CallCluster return value. Since the hits returned from ES can be typed to anything without any checks. It is advised to add functional tests that grabs the schema json file and checks that the returned usage matches the types exactly.
+
+* Fields in the schema that are never collected. If you are trying to report a field from ES but that value is never stored in ES, the check will not be able to detect if that field is ever collected in the first palce. It is advised to add unit/functional tests to check that all the fields are being reported as expected.
+
+The tool looks for `.telemetryrc.json` files in the root of the project and in the `x-pack` dir for its runtime configurations.
+
+Currently auto-fixer (`--fix`) can automatically fix the json files with the following errors:
+
+* incompatible schema - this error means that the collector schema was changed but the stored json schema file was not updated.
+
+* unused schemas - this error means that a collector was removed or its `type` renamed, the json schema file contains a schema that does not have a corrisponding collector.
+
+### Usage
+
+```bash
+node scripts/telemetry_check --fix
+```
+
+* `--path` specifies a collector path instead of checking all collectors specified in the `.telemetryrc.json` files. Accepts a `.ts` file. The file must be discoverable by at least one rc file.
+* `--fix` tells the tool to try to fix as many violations as possible. All errors that tool won't be able to fix will be reported.
diff --git a/src/legacy/core_plugins/testbed/public/testbed.js b/packages/kbn-telemetry-tools/babel.config.js
similarity index 78%
rename from src/legacy/core_plugins/testbed/public/testbed.js
rename to packages/kbn-telemetry-tools/babel.config.js
index 13005a6106ca4e..3b09c7d74ccb56 100644
--- a/src/legacy/core_plugins/testbed/public/testbed.js
+++ b/packages/kbn-telemetry-tools/babel.config.js
@@ -17,13 +17,7 @@
* under the License.
*/
-import uiRoutes from 'ui/routes';
-import template from './testbed.html';
-
-uiRoutes.when('/testbed', {
- template: template,
- controllerAs: 'testbed',
- controller: class TestbedController {
- constructor() {}
- },
-});
+module.exports = {
+ presets: ['@kbn/babel-preset/node_preset'],
+ ignore: ['**/*.test.ts', '**/__fixture__/**'],
+};
diff --git a/packages/kbn-telemetry-tools/package.json b/packages/kbn-telemetry-tools/package.json
new file mode 100644
index 00000000000000..5593a72ecd965a
--- /dev/null
+++ b/packages/kbn-telemetry-tools/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "@kbn/telemetry-tools",
+ "version": "1.0.0",
+ "license": "Apache-2.0",
+ "main": "./target/index.js",
+ "private": true,
+ "scripts": {
+ "build": "babel src --out-dir target --delete-dir-on-start --extensions .ts --source-maps=inline",
+ "kbn:bootstrap": "yarn build",
+ "kbn:watch": "yarn build --watch"
+ },
+ "devDependencies": {
+ "lodash": "npm:@elastic/lodash@3.10.1-kibana4",
+ "@kbn/dev-utils": "1.0.0",
+ "@kbn/utility-types": "1.0.0",
+ "@types/normalize-path": "^3.0.0",
+ "normalize-path": "^3.0.0",
+ "@types/lodash": "^3.10.1",
+ "moment": "^2.24.0",
+ "typescript": "3.9.5"
+ }
+}
diff --git a/packages/kbn-telemetry-tools/src/cli/run_telemetry_check.ts b/packages/kbn-telemetry-tools/src/cli/run_telemetry_check.ts
new file mode 100644
index 00000000000000..116c484a5c36af
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/cli/run_telemetry_check.ts
@@ -0,0 +1,109 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Listr from 'listr';
+import chalk from 'chalk';
+import { createFailError, run } from '@kbn/dev-utils';
+
+import {
+ createTaskContext,
+ ErrorReporter,
+ parseConfigsTask,
+ extractCollectorsTask,
+ checkMatchingSchemasTask,
+ generateSchemasTask,
+ checkCompatibleTypesTask,
+ writeToFileTask,
+ TaskContext,
+} from '../tools/tasks';
+
+export function runTelemetryCheck() {
+ run(
+ async ({ flags: { fix = false, path }, log }) => {
+ if (typeof fix !== 'boolean') {
+ throw createFailError(`${chalk.white.bgRed(' TELEMETRY ERROR ')} --fix can't have a value`);
+ }
+
+ if (typeof path === 'boolean') {
+ throw createFailError(`${chalk.white.bgRed(' TELEMETRY ERROR ')} --path require a value`);
+ }
+
+ if (fix && typeof path !== 'undefined') {
+ throw createFailError(
+ `${chalk.white.bgRed(' TELEMETRY ERROR ')} --fix is incompatible with --path flag.`
+ );
+ }
+
+ const list = new Listr([
+ {
+ title: 'Checking .telemetryrc.json files',
+ task: () => new Listr(parseConfigsTask(), { exitOnError: true }),
+ },
+ {
+ title: 'Extracting Collectors',
+ task: (context) => new Listr(extractCollectorsTask(context, path), { exitOnError: true }),
+ },
+ {
+ title: 'Checking Compatible collector.schema with collector.fetch type',
+ task: (context) => new Listr(checkCompatibleTypesTask(context), { exitOnError: true }),
+ },
+ {
+ title: 'Checking Matching collector.schema against stored json files',
+ task: (context) => new Listr(checkMatchingSchemasTask(context), { exitOnError: true }),
+ },
+ {
+ enabled: (_) => fix,
+ skip: ({ roots }: TaskContext) => {
+ return roots.every(({ esMappingDiffs }) => !esMappingDiffs || !esMappingDiffs.length);
+ },
+ title: 'Generating new telemetry mappings',
+ task: (context) => new Listr(generateSchemasTask(context), { exitOnError: true }),
+ },
+ {
+ enabled: (_) => fix,
+ skip: ({ roots }: TaskContext) => {
+ return roots.every(({ esMappingDiffs }) => !esMappingDiffs || !esMappingDiffs.length);
+ },
+ title: 'Updating telemetry mapping files',
+ task: (context) => new Listr(writeToFileTask(context), { exitOnError: true }),
+ },
+ ]);
+
+ try {
+ const context = createTaskContext();
+ await list.run(context);
+ } catch (error) {
+ process.exitCode = 1;
+ if (error instanceof ErrorReporter) {
+ error.errors.forEach((e: string | Error) => log.error(e));
+ } else {
+ log.error('Unhandled exception!');
+ log.error(error);
+ }
+ }
+ process.exit();
+ },
+ {
+ flags: {
+ allowUnexpected: true,
+ guessTypesForUnexpectedFlags: true,
+ },
+ }
+ );
+}
diff --git a/packages/kbn-telemetry-tools/src/cli/run_telemetry_extract.ts b/packages/kbn-telemetry-tools/src/cli/run_telemetry_extract.ts
new file mode 100644
index 00000000000000..27a406a4e216d2
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/cli/run_telemetry_extract.ts
@@ -0,0 +1,75 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import Listr from 'listr';
+import { run } from '@kbn/dev-utils';
+
+import {
+ createTaskContext,
+ ErrorReporter,
+ parseConfigsTask,
+ extractCollectorsTask,
+ generateSchemasTask,
+ writeToFileTask,
+} from '../tools/tasks';
+
+export function runTelemetryExtract() {
+ run(
+ async ({ flags: {}, log }) => {
+ const list = new Listr([
+ {
+ title: 'Parsing .telemetryrc.json files',
+ task: () => new Listr(parseConfigsTask(), { exitOnError: true }),
+ },
+ {
+ title: 'Extracting Telemetry Collectors',
+ task: (context) => new Listr(extractCollectorsTask(context), { exitOnError: true }),
+ },
+ {
+ title: 'Generating Schema files',
+ task: (context) => new Listr(generateSchemasTask(context), { exitOnError: true }),
+ },
+ {
+ title: 'Writing to file',
+ task: (context) => new Listr(writeToFileTask(context), { exitOnError: true }),
+ },
+ ]);
+
+ try {
+ const context = createTaskContext();
+ await list.run(context);
+ } catch (error) {
+ process.exitCode = 1;
+ if (error instanceof ErrorReporter) {
+ error.errors.forEach((e: string | Error) => log.error(e));
+ } else {
+ log.error('Unhandled exception');
+ log.error(error);
+ }
+ }
+ process.exit();
+ },
+ {
+ flags: {
+ allowUnexpected: true,
+ guessTypesForUnexpectedFlags: true,
+ },
+ }
+ );
+}
diff --git a/packages/kbn-telemetry-tools/src/index.ts b/packages/kbn-telemetry-tools/src/index.ts
new file mode 100644
index 00000000000000..3a018a9b3002c3
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { runTelemetryCheck } from './cli/run_telemetry_check';
+export { runTelemetryExtract } from './cli/run_telemetry_extract';
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema.json b/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema.json
new file mode 100644
index 00000000000000..885fe0e38dacfe
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/mock_schema.json
@@ -0,0 +1,24 @@
+{
+ "properties": {
+ "my_working_collector": {
+ "properties": {
+ "flat": {
+ "type": "keyword"
+ },
+ "my_str": {
+ "type": "text"
+ },
+ "my_objects": {
+ "properties": {
+ "total": {
+ "type": "number"
+ },
+ "type": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_externally_defined_collector.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_externally_defined_collector.ts
new file mode 100644
index 00000000000000..fe45f6b7f30427
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_externally_defined_collector.ts
@@ -0,0 +1,68 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SyntaxKind } from 'typescript';
+import { ParsedUsageCollection } from '../ts_parser';
+
+export const parsedExternallyDefinedCollector: ParsedUsageCollection[] = [
+ [
+ 'src/fixtures/telemetry_collectors/externally_defined_collector.ts',
+ {
+ collectorName: 'from_variable_collector',
+ schema: {
+ value: {
+ locale: {
+ type: 'keyword',
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ locale: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ },
+ },
+ },
+ ],
+ [
+ 'src/fixtures/telemetry_collectors/externally_defined_collector.ts',
+ {
+ collectorName: 'from_fn_collector',
+ schema: {
+ value: {
+ locale: {
+ type: 'keyword',
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ locale: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ },
+ },
+ },
+ ],
+];
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_schema.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_schema.ts
new file mode 100644
index 00000000000000..48702520829502
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_schema.ts
@@ -0,0 +1,46 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SyntaxKind } from 'typescript';
+import { ParsedUsageCollection } from '../ts_parser';
+
+export const parsedImportedSchemaCollector: ParsedUsageCollection[] = [
+ [
+ 'src/fixtures/telemetry_collectors/imported_schema.ts',
+ {
+ collectorName: 'with_imported_schema',
+ schema: {
+ value: {
+ locale: {
+ type: 'keyword',
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ locale: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ },
+ },
+ },
+ ],
+];
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_usage_interface.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_usage_interface.ts
new file mode 100644
index 00000000000000..42ed2140b5208a
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_imported_usage_interface.ts
@@ -0,0 +1,46 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SyntaxKind } from 'typescript';
+import { ParsedUsageCollection } from '../ts_parser';
+
+export const parsedImportedUsageInterface: ParsedUsageCollection[] = [
+ [
+ 'src/fixtures/telemetry_collectors/imported_usage_interface.ts',
+ {
+ collectorName: 'imported_usage_interface_collector',
+ schema: {
+ value: {
+ locale: {
+ type: 'keyword',
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ locale: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ },
+ },
+ },
+ ],
+];
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_nested_collector.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_nested_collector.ts
new file mode 100644
index 00000000000000..ed727c15b7c86e
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_nested_collector.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SyntaxKind } from 'typescript';
+import { ParsedUsageCollection } from '../ts_parser';
+
+export const parsedNestedCollector: ParsedUsageCollection = [
+ 'src/fixtures/telemetry_collectors/nested_collector.ts',
+ {
+ collectorName: 'my_nested_collector',
+ schema: {
+ value: {
+ locale: {
+ type: 'keyword',
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ locale: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ },
+ },
+ },
+];
diff --git a/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts
new file mode 100644
index 00000000000000..25e49ea221c941
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__fixture__/parsed_working_collector.ts
@@ -0,0 +1,69 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { SyntaxKind } from 'typescript';
+import { ParsedUsageCollection } from '../ts_parser';
+
+export const parsedWorkingCollector: ParsedUsageCollection = [
+ 'src/fixtures/telemetry_collectors/working_collector.ts',
+ {
+ collectorName: 'my_working_collector',
+ schema: {
+ value: {
+ flat: {
+ type: 'keyword',
+ },
+ my_str: {
+ type: 'text',
+ },
+ my_objects: {
+ total: {
+ type: 'number',
+ },
+ type: {
+ type: 'boolean',
+ },
+ },
+ },
+ },
+ fetch: {
+ typeName: 'Usage',
+ typeDescriptor: {
+ flat: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ my_str: {
+ kind: SyntaxKind.StringKeyword,
+ type: 'StringKeyword',
+ },
+ my_objects: {
+ total: {
+ kind: SyntaxKind.NumberKeyword,
+ type: 'NumberKeyword',
+ },
+ type: {
+ kind: SyntaxKind.BooleanKeyword,
+ type: 'BooleanKeyword',
+ },
+ },
+ },
+ },
+ },
+];
diff --git a/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap b/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap
new file mode 100644
index 00000000000000..44a12dfa9030cc
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__snapshots__/extract_collectors.test.ts.snap
@@ -0,0 +1,163 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`extractCollectors extracts collectors given rc file 1`] = `
+Array [
+ Array [
+ "src/fixtures/telemetry_collectors/externally_defined_collector.ts",
+ Object {
+ "collectorName": "from_variable_collector",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "locale": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "locale": Object {
+ "type": "keyword",
+ },
+ },
+ },
+ },
+ ],
+ Array [
+ "src/fixtures/telemetry_collectors/externally_defined_collector.ts",
+ Object {
+ "collectorName": "from_fn_collector",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "locale": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "locale": Object {
+ "type": "keyword",
+ },
+ },
+ },
+ },
+ ],
+ Array [
+ "src/fixtures/telemetry_collectors/imported_schema.ts",
+ Object {
+ "collectorName": "with_imported_schema",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "locale": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "locale": Object {
+ "type": "keyword",
+ },
+ },
+ },
+ },
+ ],
+ Array [
+ "src/fixtures/telemetry_collectors/imported_usage_interface.ts",
+ Object {
+ "collectorName": "imported_usage_interface_collector",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "locale": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "locale": Object {
+ "type": "keyword",
+ },
+ },
+ },
+ },
+ ],
+ Array [
+ "src/fixtures/telemetry_collectors/nested_collector.ts",
+ Object {
+ "collectorName": "my_nested_collector",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "locale": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "locale": Object {
+ "type": "keyword",
+ },
+ },
+ },
+ },
+ ],
+ Array [
+ "src/fixtures/telemetry_collectors/working_collector.ts",
+ Object {
+ "collectorName": "my_working_collector",
+ "fetch": Object {
+ "typeDescriptor": Object {
+ "flat": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ "my_objects": Object {
+ "total": Object {
+ "kind": 140,
+ "type": "NumberKeyword",
+ },
+ "type": Object {
+ "kind": 128,
+ "type": "BooleanKeyword",
+ },
+ },
+ "my_str": Object {
+ "kind": 143,
+ "type": "StringKeyword",
+ },
+ },
+ "typeName": "Usage",
+ },
+ "schema": Object {
+ "value": Object {
+ "flat": Object {
+ "type": "keyword",
+ },
+ "my_objects": Object {
+ "total": Object {
+ "type": "number",
+ },
+ "type": Object {
+ "type": "boolean",
+ },
+ },
+ "my_str": Object {
+ "type": "text",
+ },
+ },
+ },
+ },
+ ],
+]
+`;
diff --git a/packages/kbn-telemetry-tools/src/tools/__snapshots__/ts_parser.test.ts.snap b/packages/kbn-telemetry-tools/src/tools/__snapshots__/ts_parser.test.ts.snap
new file mode 100644
index 00000000000000..5b1b3d9d352990
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/__snapshots__/ts_parser.test.ts.snap
@@ -0,0 +1,6 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parseUsageCollection throws when mapping fields is not defined 1`] = `
+"Error extracting collector in src/fixtures/telemetry_collectors/unmapped_collector.ts
+Error: usageCollector.schema must be defined."
+`;
diff --git a/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts b/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts
new file mode 100644
index 00000000000000..6083593431d9b3
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/check_collector__integrity.test.ts
@@ -0,0 +1,125 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as _ from 'lodash';
+import * as ts from 'typescript';
+import { parsedWorkingCollector } from './__fixture__/parsed_working_collector';
+import { checkCompatibleTypeDescriptor, checkMatchingMapping } from './check_collector_integrity';
+import * as path from 'path';
+import { readFile } from 'fs';
+import { promisify } from 'util';
+const read = promisify(readFile);
+
+async function parseJsonFile(relativePath: string) {
+ const schemaPath = path.resolve(__dirname, '__fixture__', relativePath);
+ const fileContent = await read(schemaPath, 'utf8');
+ return JSON.parse(fileContent);
+}
+
+describe('checkMatchingMapping', () => {
+ it('returns no diff on matching parsedCollections and stored mapping', async () => {
+ const mockSchema = await parseJsonFile('mock_schema.json');
+ const diffs = checkMatchingMapping([parsedWorkingCollector], mockSchema);
+ expect(diffs).toEqual({});
+ });
+
+ describe('Collector change', () => {
+ it('returns diff on mismatching parsedCollections and stored mapping', async () => {
+ const mockSchema = await parseJsonFile('mock_schema.json');
+ const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
+ const fieldMapping = { type: 'number' };
+ malformedParsedCollector[1].schema.value.flat = fieldMapping;
+
+ const diffs = checkMatchingMapping([malformedParsedCollector], mockSchema);
+ expect(diffs).toEqual({
+ properties: {
+ my_working_collector: {
+ properties: { flat: fieldMapping },
+ },
+ },
+ });
+ });
+
+ it('returns diff on unknown parsedCollections', async () => {
+ const mockSchema = await parseJsonFile('mock_schema.json');
+ const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
+ const collectorName = 'New Collector in town!';
+ const collectorMapping = { some_usage: { type: 'number' } };
+ malformedParsedCollector[1].collectorName = collectorName;
+ malformedParsedCollector[1].schema.value = { some_usage: { type: 'number' } };
+
+ const diffs = checkMatchingMapping([malformedParsedCollector], mockSchema);
+ expect(diffs).toEqual({
+ properties: {
+ [collectorName]: {
+ properties: collectorMapping,
+ },
+ },
+ });
+ });
+ });
+});
+
+describe('checkCompatibleTypeDescriptor', () => {
+ it('returns no diff on compatible type descriptor with mapping', () => {
+ const incompatibles = checkCompatibleTypeDescriptor([parsedWorkingCollector]);
+ expect(incompatibles).toHaveLength(0);
+ });
+
+ describe('Interface Change', () => {
+ it('returns diff on incompatible type descriptor with mapping', () => {
+ const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
+ malformedParsedCollector[1].fetch.typeDescriptor.flat.kind = ts.SyntaxKind.BooleanKeyword;
+ const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
+ expect(incompatibles).toHaveLength(1);
+ const { diff, message } = incompatibles[0];
+ expect(diff).toEqual({ 'flat.kind': 'boolean' });
+ expect(message).toHaveLength(1);
+ expect(message).toEqual([
+ 'incompatible Type key (Usage.flat): expected ("string") got ("boolean").',
+ ]);
+ });
+
+ it.todo('returns diff when missing type descriptor');
+ });
+
+ describe('Mapping change', () => {
+ it('returns no diff when mapping change between text and keyword', () => {
+ const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
+ malformedParsedCollector[1].schema.value.flat.type = 'text';
+ const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
+ expect(incompatibles).toHaveLength(0);
+ });
+
+ it('returns diff on incompatible type descriptor with mapping', () => {
+ const malformedParsedCollector = _.cloneDeep(parsedWorkingCollector);
+ malformedParsedCollector[1].schema.value.flat.type = 'boolean';
+ const incompatibles = checkCompatibleTypeDescriptor([malformedParsedCollector]);
+ expect(incompatibles).toHaveLength(1);
+ const { diff, message } = incompatibles[0];
+ expect(diff).toEqual({ 'flat.kind': 'string' });
+ expect(message).toHaveLength(1);
+ expect(message).toEqual([
+ 'incompatible Type key (Usage.flat): expected ("boolean") got ("string").',
+ ]);
+ });
+
+ it.todo('returns diff when missing mapping');
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/check_collector_integrity.ts b/packages/kbn-telemetry-tools/src/tools/check_collector_integrity.ts
new file mode 100644
index 00000000000000..824132b05732ce
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/check_collector_integrity.ts
@@ -0,0 +1,103 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as _ from 'lodash';
+import { difference, flattenKeys, pickDeep } from './utils';
+import { ParsedUsageCollection } from './ts_parser';
+import { generateMapping, compatibleSchemaTypes } from './manage_schema';
+import { kindToDescriptorName } from './serializer';
+
+export function checkMatchingMapping(
+ UsageCollections: ParsedUsageCollection[],
+ esMapping: any
+): any {
+ const generatedMapping = generateMapping(UsageCollections);
+ return difference(generatedMapping, esMapping);
+}
+
+interface IncompatibleDescriptor {
+ diff: Record;
+ collectorPath: string;
+ message: string[];
+}
+export function checkCompatibleTypeDescriptor(
+ usageCollections: ParsedUsageCollection[]
+): IncompatibleDescriptor[] {
+ const results: Array = usageCollections.map(
+ ([collectorPath, collectorDetails]) => {
+ const typeDescriptorTypes = flattenKeys(
+ pickDeep(collectorDetails.fetch.typeDescriptor, 'kind')
+ );
+ const typeDescriptorKinds = _.reduce(
+ typeDescriptorTypes,
+ (acc: any, type: number, key: string) => {
+ try {
+ acc[key] = kindToDescriptorName(type);
+ } catch (err) {
+ throw Error(`Unrecognized type (${key}: ${type}) in ${collectorPath}`);
+ }
+ return acc;
+ },
+ {} as any
+ );
+
+ const schemaTypes = flattenKeys(pickDeep(collectorDetails.schema.value, 'type'));
+ const transformedMappingKinds = _.reduce(
+ schemaTypes,
+ (acc: any, type: string, key: string) => {
+ try {
+ acc[key.replace(/.type$/, '.kind')] = compatibleSchemaTypes(type as any);
+ } catch (err) {
+ throw Error(`Unrecognized type (${key}: ${type}) in ${collectorPath}`);
+ }
+ return acc;
+ },
+ {} as any
+ );
+
+ const diff: any = difference(typeDescriptorKinds, transformedMappingKinds);
+ const diffEntries = Object.entries(diff);
+
+ if (!diffEntries.length) {
+ return false;
+ }
+
+ return {
+ diff,
+ collectorPath,
+ message: diffEntries.map(([key]) => {
+ const interfaceKey = key.replace('.kind', '');
+ try {
+ const expectedDescriptorType = JSON.stringify(transformedMappingKinds[key], null, 2);
+ const actualDescriptorType = JSON.stringify(typeDescriptorKinds[key], null, 2);
+ return `incompatible Type key (${collectorDetails.fetch.typeName}.${interfaceKey}): expected (${expectedDescriptorType}) got (${actualDescriptorType}).`;
+ } catch (err) {
+ throw Error(`Error converting ${key} in ${collectorPath}.\n${err}`);
+ }
+ }),
+ };
+ }
+ );
+
+ return results.filter((entry): entry is IncompatibleDescriptor => entry !== false);
+}
+
+export function checkCollectorIntegrity(UsageCollections: ParsedUsageCollection[], esMapping: any) {
+ return UsageCollections;
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/config.test.ts b/packages/kbn-telemetry-tools/src/tools/config.test.ts
new file mode 100644
index 00000000000000..51ca0493cbb5a4
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/config.test.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as path from 'path';
+import { parseTelemetryRC } from './config';
+
+describe('parseTelemetryRC', () => {
+ it('throw if config path is not absolute', async () => {
+ const fixtureDir = './__fixture__/';
+ await expect(parseTelemetryRC(fixtureDir)).rejects.toThrowError();
+ });
+
+ it('returns parsed rc file', async () => {
+ const configRoot = path.join(process.cwd(), 'src', 'fixtures', 'telemetry_collectors');
+ const config = await parseTelemetryRC(configRoot);
+ expect(config).toStrictEqual([
+ {
+ root: configRoot,
+ output: configRoot,
+ exclude: [path.resolve(configRoot, './unmapped_collector.ts')],
+ },
+ ]);
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/config.ts b/packages/kbn-telemetry-tools/src/tools/config.ts
new file mode 100644
index 00000000000000..5724b869e8f5ea
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/config.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as path from 'path';
+import { readFileAsync } from './utils';
+import { TELEMETRY_RC } from './constants';
+
+export interface TelemetryRC {
+ root: string;
+ output: string;
+ exclude: string[];
+}
+
+export async function readRcFile(rcRoot: string) {
+ if (!path.isAbsolute(rcRoot)) {
+ throw Error(`config root (${rcRoot}) must be an absolute path.`);
+ }
+
+ const rcFile = path.resolve(rcRoot, TELEMETRY_RC);
+ const configString = await readFileAsync(rcFile, 'utf8');
+ return JSON.parse(configString);
+}
+
+export async function parseTelemetryRC(rcRoot: string): Promise {
+ const parsedRc = await readRcFile(rcRoot);
+ const configs = Array.isArray(parsedRc) ? parsedRc : [parsedRc];
+ return configs.map(({ root, output, exclude = [] }) => {
+ if (typeof root !== 'string') {
+ throw Error('config.root must be a string.');
+ }
+ if (typeof output !== 'string') {
+ throw Error('config.output must be a string.');
+ }
+ if (!Array.isArray(exclude)) {
+ throw Error('config.exclude must be an array of strings.');
+ }
+
+ return {
+ root: path.join(rcRoot, root),
+ output: path.join(rcRoot, output),
+ exclude: exclude.map((excludedPath) => path.resolve(rcRoot, excludedPath)),
+ };
+ });
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/constants.ts b/packages/kbn-telemetry-tools/src/tools/constants.ts
new file mode 100644
index 00000000000000..8635b1a2e2528e
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/constants.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const TELEMETRY_RC = '.telemetryrc.json';
diff --git a/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts b/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts
new file mode 100644
index 00000000000000..1b4ed21a1635cf
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/extract_collectors.test.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import * as path from 'path';
+import { extractCollectors, getProgramPaths } from './extract_collectors';
+import { parseTelemetryRC } from './config';
+
+describe('extractCollectors', () => {
+ it('extracts collectors given rc file', async () => {
+ const configRoot = path.join(process.cwd(), 'src', 'fixtures', 'telemetry_collectors');
+ const tsConfig = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json');
+ if (!tsConfig) {
+ throw new Error('Could not find a valid tsconfig.json.');
+ }
+ const configs = await parseTelemetryRC(configRoot);
+ expect(configs).toHaveLength(1);
+ const programPaths = await getProgramPaths(configs[0]);
+
+ const results = [...extractCollectors(programPaths, tsConfig)];
+ expect(results).toHaveLength(6);
+ expect(results).toMatchSnapshot();
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/extract_collectors.ts b/packages/kbn-telemetry-tools/src/tools/extract_collectors.ts
new file mode 100644
index 00000000000000..a638fde0214580
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/extract_collectors.ts
@@ -0,0 +1,75 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import * as path from 'path';
+import { parseUsageCollection } from './ts_parser';
+import { globAsync } from './utils';
+import { TelemetryRC } from './config';
+
+export async function getProgramPaths({
+ root,
+ exclude,
+}: Pick): Promise {
+ const filePaths = await globAsync('**/*.ts', {
+ cwd: root,
+ ignore: [
+ '**/node_modules/**',
+ '**/*.test.*',
+ '**/*.mock.*',
+ '**/mocks.*',
+ '**/__fixture__/**',
+ '**/__tests__/**',
+ '**/public/**',
+ '**/dist/**',
+ '**/target/**',
+ '**/*.d.ts',
+ ],
+ });
+
+ if (filePaths.length === 0) {
+ throw Error(`No files found in ${root}`);
+ }
+
+ const fullPaths = filePaths
+ .map((filePath) => path.join(root, filePath))
+ .filter((fullPath) => !exclude.some((excludedPath) => fullPath.startsWith(excludedPath)));
+
+ if (fullPaths.length === 0) {
+ throw Error(`No paths covered from ${root} by the .telemetryrc.json`);
+ }
+
+ return fullPaths;
+}
+
+export function* extractCollectors(fullPaths: string[], tsConfig: any) {
+ const program = ts.createProgram(fullPaths, tsConfig);
+ program.getTypeChecker();
+ const sourceFiles = fullPaths.map((fullPath) => {
+ const sourceFile = program.getSourceFile(fullPath);
+ if (!sourceFile) {
+ throw Error(`Unable to get sourceFile ${fullPath}.`);
+ }
+ return sourceFile;
+ });
+
+ for (const sourceFile of sourceFiles) {
+ yield* parseUsageCollection(sourceFile, program);
+ }
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts b/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts
new file mode 100644
index 00000000000000..8f4bfc66b32aeb
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/manage_schema.test.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { generateMapping } from './manage_schema';
+import { parsedWorkingCollector } from './__fixture__/parsed_working_collector';
+import * as path from 'path';
+import { readFile } from 'fs';
+import { promisify } from 'util';
+const read = promisify(readFile);
+
+async function parseJsonFile(relativePath: string) {
+ const schemaPath = path.resolve(__dirname, '__fixture__', relativePath);
+ const fileContent = await read(schemaPath, 'utf8');
+ return JSON.parse(fileContent);
+}
+
+describe('generateMapping', () => {
+ it('generates a mapping file', async () => {
+ const mockSchema = await parseJsonFile('mock_schema.json');
+ const result = generateMapping([parsedWorkingCollector]);
+ expect(result).toEqual(mockSchema);
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/manage_schema.ts b/packages/kbn-telemetry-tools/src/tools/manage_schema.ts
new file mode 100644
index 00000000000000..d422837140d802
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/manage_schema.ts
@@ -0,0 +1,86 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { ParsedUsageCollection } from './ts_parser';
+
+export type AllowedSchemaTypes =
+ | 'keyword'
+ | 'text'
+ | 'number'
+ | 'boolean'
+ | 'long'
+ | 'date'
+ | 'float';
+
+export function compatibleSchemaTypes(type: AllowedSchemaTypes) {
+ switch (type) {
+ case 'keyword':
+ case 'text':
+ case 'date':
+ return 'string';
+ case 'boolean':
+ return 'boolean';
+ case 'number':
+ case 'float':
+ case 'long':
+ return 'number';
+ default:
+ throw new Error(`Unknown schema type ${type}`);
+ }
+}
+
+export function isObjectMapping(entity: any) {
+ if (typeof entity === 'object') {
+ // 'type' is explicitly specified to be an object.
+ if (typeof entity.type === 'string' && entity.type === 'object') {
+ return true;
+ }
+
+ // 'type' is not set; ES defaults to object mapping for when type is unspecified.
+ if (typeof entity.type === 'undefined') {
+ return true;
+ }
+
+ // 'type' is a field in the mapping and is not the type of the mapping.
+ if (typeof entity.type === 'object') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+function transformToEsMapping(usageMappingValue: any) {
+ const fieldMapping: any = { properties: {} };
+ for (const [key, value] of Object.entries(usageMappingValue)) {
+ fieldMapping.properties[key] = isObjectMapping(value) ? transformToEsMapping(value) : value;
+ }
+ return fieldMapping;
+}
+
+export function generateMapping(usageCollections: ParsedUsageCollection[]) {
+ const esMapping: any = { properties: {} };
+ for (const [, collecionDetails] of usageCollections) {
+ esMapping.properties[collecionDetails.collectorName] = transformToEsMapping(
+ collecionDetails.schema.value
+ );
+ }
+
+ return esMapping;
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/serializer.test.ts b/packages/kbn-telemetry-tools/src/tools/serializer.test.ts
new file mode 100644
index 00000000000000..9475574a442192
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/serializer.test.ts
@@ -0,0 +1,105 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import * as path from 'path';
+import { getDescriptor, TelemetryKinds } from './serializer';
+import { traverseNodes } from './ts_parser';
+
+export function loadFixtureProgram(fixtureName: string) {
+ const fixturePath = path.resolve(
+ process.cwd(),
+ 'src',
+ 'fixtures',
+ 'telemetry_collectors',
+ `${fixtureName}.ts`
+ );
+ const tsConfig = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json');
+ if (!tsConfig) {
+ throw new Error('Could not find a valid tsconfig.json.');
+ }
+ const program = ts.createProgram([fixturePath], tsConfig as any);
+ const checker = program.getTypeChecker();
+ const sourceFile = program.getSourceFile(fixturePath);
+ if (!sourceFile) {
+ throw Error('sourceFile is undefined!');
+ }
+ return { program, checker, sourceFile };
+}
+
+describe('getDescriptor', () => {
+ const usageInterfaces = new Map();
+ let tsProgram: ts.Program;
+ beforeAll(() => {
+ const { program, sourceFile } = loadFixtureProgram('constants');
+ tsProgram = program;
+ for (const node of traverseNodes(sourceFile)) {
+ if (ts.isInterfaceDeclaration(node)) {
+ const interfaceName = node.name.getText();
+ usageInterfaces.set(interfaceName, node);
+ }
+ }
+ });
+
+ it('serializes flat types', () => {
+ const usageInterface = usageInterfaces.get('Usage');
+ const descriptor = getDescriptor(usageInterface!, tsProgram);
+ expect(descriptor).toEqual({
+ locale: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' },
+ });
+ });
+
+ it('serializes union types', () => {
+ const usageInterface = usageInterfaces.get('WithUnion');
+ const descriptor = getDescriptor(usageInterface!, tsProgram);
+
+ expect(descriptor).toEqual({
+ prop1: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' },
+ prop2: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' },
+ prop3: { kind: ts.SyntaxKind.StringKeyword, type: 'StringKeyword' },
+ prop4: { kind: ts.SyntaxKind.StringLiteral, type: 'StringLiteral' },
+ prop5: { kind: ts.SyntaxKind.FirstLiteralToken, type: 'FirstLiteralToken' },
+ });
+ });
+
+ it('serializes Moment Dates', () => {
+ const usageInterface = usageInterfaces.get('WithMoment');
+ const descriptor = getDescriptor(usageInterface!, tsProgram);
+ expect(descriptor).toEqual({
+ prop1: { kind: TelemetryKinds.MomentDate, type: 'MomentDate' },
+ prop2: { kind: TelemetryKinds.MomentDate, type: 'MomentDate' },
+ prop3: { kind: TelemetryKinds.MomentDate, type: 'MomentDate' },
+ prop4: { kind: TelemetryKinds.Date, type: 'Date' },
+ });
+ });
+
+ it('throws error on conflicting union types', () => {
+ const usageInterface = usageInterfaces.get('WithConflictingUnion');
+ expect(() => getDescriptor(usageInterface!, tsProgram)).toThrowError(
+ 'Mapping does not support conflicting union types.'
+ );
+ });
+
+ it('throws error on unsupported union types', () => {
+ const usageInterface = usageInterfaces.get('WithUnsupportedUnion');
+ expect(() => getDescriptor(usageInterface!, tsProgram)).toThrowError(
+ 'Mapping does not support conflicting union types.'
+ );
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/serializer.ts b/packages/kbn-telemetry-tools/src/tools/serializer.ts
new file mode 100644
index 00000000000000..bce5dd7f58643b
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/serializer.ts
@@ -0,0 +1,169 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import { uniq } from 'lodash';
+import {
+ getResolvedModuleSourceFile,
+ getIdentifierDeclarationFromSource,
+ getModuleSpecifier,
+} from './utils';
+
+export enum TelemetryKinds {
+ MomentDate = 1000,
+ Date = 10001,
+}
+
+interface DescriptorValue {
+ kind: ts.SyntaxKind | TelemetryKinds;
+ type: keyof typeof ts.SyntaxKind | keyof typeof TelemetryKinds;
+}
+
+export interface Descriptor {
+ [name: string]: Descriptor | DescriptorValue;
+}
+
+export function isObjectDescriptor(value: any) {
+ if (typeof value === 'object') {
+ if (typeof value.type === 'string' && value.type === 'object') {
+ return true;
+ }
+
+ if (typeof value.type === 'undefined') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+export function kindToDescriptorName(kind: number) {
+ switch (kind) {
+ case ts.SyntaxKind.StringKeyword:
+ case ts.SyntaxKind.StringLiteral:
+ case ts.SyntaxKind.SetKeyword:
+ case TelemetryKinds.Date:
+ case TelemetryKinds.MomentDate:
+ return 'string';
+ case ts.SyntaxKind.BooleanKeyword:
+ return 'boolean';
+ case ts.SyntaxKind.NumberKeyword:
+ case ts.SyntaxKind.NumericLiteral:
+ return 'number';
+ default:
+ throw new Error(`Unknown kind ${kind}`);
+ }
+}
+
+export function getDescriptor(node: ts.Node, program: ts.Program): Descriptor | DescriptorValue {
+ if (ts.isMethodSignature(node) || ts.isPropertySignature(node)) {
+ if (node.type) {
+ return getDescriptor(node.type, program);
+ }
+ }
+ if (ts.isTypeLiteralNode(node) || ts.isInterfaceDeclaration(node)) {
+ return node.members.reduce((acc, m) => {
+ acc[m.name?.getText() || ''] = getDescriptor(m, program);
+ return acc;
+ }, {} as any);
+ }
+
+ if (ts.SyntaxKind.FirstNode === node.kind) {
+ return getDescriptor((node as any).right, program);
+ }
+
+ if (ts.isIdentifier(node)) {
+ const identifierName = node.getText();
+ if (identifierName === 'Date') {
+ return { kind: TelemetryKinds.Date, type: 'Date' };
+ }
+ if (identifierName === 'Moment') {
+ return { kind: TelemetryKinds.MomentDate, type: 'MomentDate' };
+ }
+ throw new Error(`Unsupported Identifier ${identifierName}.`);
+ }
+
+ if (ts.isTypeReferenceNode(node)) {
+ const typeChecker = program.getTypeChecker();
+ const symbol = typeChecker.getSymbolAtLocation(node.typeName);
+ const symbolName = symbol?.getName();
+ if (symbolName === 'Moment') {
+ return { kind: TelemetryKinds.MomentDate, type: 'MomentDate' };
+ }
+ if (symbolName === 'Date') {
+ return { kind: TelemetryKinds.Date, type: 'Date' };
+ }
+ const declaration = (symbol?.getDeclarations() || [])[0];
+ if (declaration) {
+ return getDescriptor(declaration, program);
+ }
+ return getDescriptor(node.typeName, program);
+ }
+
+ if (ts.isImportSpecifier(node)) {
+ const source = node.getSourceFile();
+ const importedModuleName = getModuleSpecifier(node);
+
+ const declarationSource = getResolvedModuleSourceFile(source, program, importedModuleName);
+ const declarationNode = getIdentifierDeclarationFromSource(node.name, declarationSource);
+ return getDescriptor(declarationNode, program);
+ }
+
+ if (ts.isArrayTypeNode(node)) {
+ return getDescriptor(node.elementType, program);
+ }
+
+ if (ts.isLiteralTypeNode(node)) {
+ return {
+ kind: node.literal.kind,
+ type: ts.SyntaxKind[node.literal.kind] as keyof typeof ts.SyntaxKind,
+ };
+ }
+
+ if (ts.isUnionTypeNode(node)) {
+ const types = node.types.filter((typeNode) => {
+ return (
+ typeNode.kind !== ts.SyntaxKind.NullKeyword &&
+ typeNode.kind !== ts.SyntaxKind.UndefinedKeyword
+ );
+ });
+
+ const kinds = types.map((typeNode) => getDescriptor(typeNode, program));
+
+ const uniqueKinds = uniq(kinds, 'kind');
+
+ if (uniqueKinds.length !== 1) {
+ throw Error('Mapping does not support conflicting union types.');
+ }
+
+ return uniqueKinds[0];
+ }
+
+ switch (node.kind) {
+ case ts.SyntaxKind.NumberKeyword:
+ case ts.SyntaxKind.BooleanKeyword:
+ case ts.SyntaxKind.StringKeyword:
+ case ts.SyntaxKind.SetKeyword:
+ return { kind: node.kind, type: ts.SyntaxKind[node.kind] as keyof typeof ts.SyntaxKind };
+ case ts.SyntaxKind.UnionType:
+ case ts.SyntaxKind.AnyKeyword:
+ default:
+ throw new Error(`Unknown type ${ts.SyntaxKind[node.kind]}; ${node.getText()}`);
+ }
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/check_compatible_types_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/check_compatible_types_task.ts
new file mode 100644
index 00000000000000..dae4d0f1ad168a
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/check_compatible_types_task.ts
@@ -0,0 +1,43 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { TaskContext } from './task_context';
+import { checkCompatibleTypeDescriptor } from '../check_collector_integrity';
+
+export function checkCompatibleTypesTask({ reporter, roots }: TaskContext) {
+ return roots.map((root) => ({
+ task: async () => {
+ if (root.parsedCollections) {
+ const differences = checkCompatibleTypeDescriptor(root.parsedCollections);
+ const reporterWithContext = reporter.withContext({ name: root.config.root });
+ if (differences.length) {
+ reporterWithContext.report(
+ `${JSON.stringify(
+ differences,
+ null,
+ 2
+ )}. \nPlease fix the collectors and run the check again.`
+ );
+ throw reporter;
+ }
+ }
+ },
+ title: `Checking in ${root.config.root}`,
+ }));
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/check_matching_schemas_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/check_matching_schemas_task.ts
new file mode 100644
index 00000000000000..a1f23bcd44c765
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/check_matching_schemas_task.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as path from 'path';
+import { TaskContext } from './task_context';
+import { checkMatchingMapping } from '../check_collector_integrity';
+import { readFileAsync } from '../utils';
+
+export function checkMatchingSchemasTask({ roots }: TaskContext) {
+ return roots.map((root) => ({
+ task: async () => {
+ const fullPath = path.resolve(process.cwd(), root.config.output);
+ const esMappingString = await readFileAsync(fullPath, 'utf-8');
+ const esMapping = JSON.parse(esMappingString);
+
+ if (root.parsedCollections) {
+ const differences = checkMatchingMapping(root.parsedCollections, esMapping);
+
+ root.esMappingDiffs = Object.keys(differences);
+ }
+ },
+ title: `Checking in ${root.config.root}`,
+ }));
+}
diff --git a/src/plugins/data/common/index_patterns/index_patterns/types.ts b/packages/kbn-telemetry-tools/src/tools/tasks/error_reporter.ts
similarity index 67%
rename from src/plugins/data/common/index_patterns/index_patterns/types.ts
rename to packages/kbn-telemetry-tools/src/tools/tasks/error_reporter.ts
index b2060dd1d48bac..246d659667281e 100644
--- a/src/plugins/data/common/index_patterns/index_patterns/types.ts
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/error_reporter.ts
@@ -17,19 +17,18 @@
* under the License.
*/
-export type AggregationRestrictions = Record<
- string,
- {
- agg?: string;
- interval?: number;
- fixed_interval?: string;
- calendar_interval?: string;
- delay?: string;
- time_zone?: string;
- }
->;
+import chalk from 'chalk';
+import { normalizePath } from '../utils';
+
+export class ErrorReporter {
+ errors: string[] = [];
-export interface TypeMeta {
- aggs?: Record;
- [key: string]: any;
+ withContext(context: any) {
+ return { report: (error: any) => this.report(error, context) };
+ }
+ report(error: any, context: any) {
+ this.errors.push(
+ `${chalk.white.bgRed(' TELEMETRY ERROR ')} Error in ${normalizePath(context.name)}\n${error}`
+ );
+ }
}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/extract_collectors_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/extract_collectors_task.ts
new file mode 100644
index 00000000000000..834ec71e220320
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/extract_collectors_task.ts
@@ -0,0 +1,58 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import * as path from 'path';
+import { TaskContext } from './task_context';
+import { extractCollectors, getProgramPaths } from '../extract_collectors';
+
+export function extractCollectorsTask(
+ { roots }: TaskContext,
+ restrictProgramToPath?: string | string[]
+) {
+ return roots.map((root) => ({
+ task: async () => {
+ const tsConfig = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json');
+ if (!tsConfig) {
+ throw new Error('Could not find a valid tsconfig.json.');
+ }
+ const programPaths = await getProgramPaths(root.config);
+
+ if (typeof restrictProgramToPath !== 'undefined') {
+ const restrictProgramToPaths = Array.isArray(restrictProgramToPath)
+ ? restrictProgramToPath
+ : [restrictProgramToPath];
+
+ const fullRestrictedPaths = restrictProgramToPaths.map((collectorPath) =>
+ path.resolve(process.cwd(), collectorPath)
+ );
+ const restrictedProgramPaths = programPaths.filter((programPath) =>
+ fullRestrictedPaths.includes(programPath)
+ );
+ if (restrictedProgramPaths.length) {
+ root.parsedCollections = [...extractCollectors(restrictedProgramPaths, tsConfig)];
+ }
+ return;
+ }
+
+ root.parsedCollections = [...extractCollectors(programPaths, tsConfig)];
+ },
+ title: `Extracting collectors in ${root.config.root}`,
+ }));
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/generate_schemas_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/generate_schemas_task.ts
new file mode 100644
index 00000000000000..f6d15c7127d4eb
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/generate_schemas_task.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as _ from 'lodash';
+import { TaskContext } from './task_context';
+import { generateMapping } from '../manage_schema';
+
+export function generateSchemasTask({ roots }: TaskContext) {
+ return roots.map((root) => ({
+ task: () => {
+ if (!root.parsedCollections || !root.parsedCollections.length) {
+ return;
+ }
+ const mapping = generateMapping(root.parsedCollections);
+ root.mapping = mapping;
+ },
+ title: `Generating mapping for ${root.config.root}`,
+ }));
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/index.ts b/packages/kbn-telemetry-tools/src/tools/tasks/index.ts
new file mode 100644
index 00000000000000..cbe74aeb483e41
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/index.ts
@@ -0,0 +1,28 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export { ErrorReporter } from './error_reporter';
+export { TaskContext, createTaskContext } from './task_context';
+
+export { parseConfigsTask } from './parse_configs_task';
+export { extractCollectorsTask } from './extract_collectors_task';
+export { generateSchemasTask } from './generate_schemas_task';
+export { writeToFileTask } from './write_to_file_task';
+export { checkMatchingSchemasTask } from './check_matching_schemas_task';
+export { checkCompatibleTypesTask } from './check_compatible_types_task';
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/parse_configs_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/parse_configs_task.ts
new file mode 100644
index 00000000000000..00b319006e2ee3
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/parse_configs_task.ts
@@ -0,0 +1,46 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as path from 'path';
+import { parseTelemetryRC } from '../config';
+import { TaskContext } from './task_context';
+
+export function parseConfigsTask() {
+ const kibanaRoot = process.cwd();
+ const xpackRoot = path.join(kibanaRoot, 'x-pack');
+
+ const configRoots = [kibanaRoot, xpackRoot];
+
+ return configRoots.map((configRoot) => ({
+ task: async (context: TaskContext) => {
+ try {
+ const configs = await parseTelemetryRC(configRoot);
+ configs.forEach((config) => {
+ context.roots.push({ config });
+ });
+ } catch (err) {
+ const { reporter } = context;
+ const reporterWithContext = reporter.withContext({ name: configRoot });
+ reporterWithContext.report(err);
+ throw reporter;
+ }
+ },
+ title: `Parsing configs in ${configRoot}`,
+ }));
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/task_context.ts b/packages/kbn-telemetry-tools/src/tools/tasks/task_context.ts
new file mode 100644
index 00000000000000..78d0b7fbd6c2d7
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/task_context.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { TelemetryRC } from '../config';
+import { ErrorReporter } from './error_reporter';
+import { ParsedUsageCollection } from '../ts_parser';
+export interface TelemetryRoot {
+ config: TelemetryRC;
+ parsedCollections?: ParsedUsageCollection[];
+ mapping?: any;
+ esMappingDiffs?: string[];
+}
+
+export interface TaskContext {
+ reporter: ErrorReporter;
+ roots: TelemetryRoot[];
+}
+
+export function createTaskContext(): TaskContext {
+ const reporter = new ErrorReporter();
+ return {
+ roots: [],
+ reporter,
+ };
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/tasks/write_to_file_task.ts b/packages/kbn-telemetry-tools/src/tools/tasks/write_to_file_task.ts
new file mode 100644
index 00000000000000..fcfc09db65426f
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/tasks/write_to_file_task.ts
@@ -0,0 +1,35 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as path from 'path';
+import { writeFileAsync } from '../utils';
+import { TaskContext } from './task_context';
+
+export function writeToFileTask({ roots }: TaskContext) {
+ return roots.map((root) => ({
+ task: async () => {
+ const fullPath = path.resolve(process.cwd(), root.config.output);
+ if (root.mapping && Object.keys(root.mapping.properties).length > 0) {
+ const serializedMapping = JSON.stringify(root.mapping, null, 2).concat('\n');
+ await writeFileAsync(fullPath, serializedMapping);
+ }
+ },
+ title: `Writing mapping for ${root.config.root}`,
+ }));
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/ts_parser.test.ts b/packages/kbn-telemetry-tools/src/tools/ts_parser.test.ts
new file mode 100644
index 00000000000000..b7ca33a7bcd743
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/ts_parser.test.ts
@@ -0,0 +1,94 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { parseUsageCollection } from './ts_parser';
+import * as ts from 'typescript';
+import * as path from 'path';
+import { parsedWorkingCollector } from './__fixture__/parsed_working_collector';
+import { parsedNestedCollector } from './__fixture__/parsed_nested_collector';
+import { parsedExternallyDefinedCollector } from './__fixture__/parsed_externally_defined_collector';
+import { parsedImportedUsageInterface } from './__fixture__/parsed_imported_usage_interface';
+import { parsedImportedSchemaCollector } from './__fixture__/parsed_imported_schema';
+
+export function loadFixtureProgram(fixtureName: string) {
+ const fixturePath = path.resolve(
+ process.cwd(),
+ 'src',
+ 'fixtures',
+ 'telemetry_collectors',
+ `${fixtureName}.ts`
+ );
+ const tsConfig = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json');
+ if (!tsConfig) {
+ throw new Error('Could not find a valid tsconfig.json.');
+ }
+ const program = ts.createProgram([fixturePath], tsConfig as any);
+ const checker = program.getTypeChecker();
+ const sourceFile = program.getSourceFile(fixturePath);
+ if (!sourceFile) {
+ throw Error('sourceFile is undefined!');
+ }
+ return { program, checker, sourceFile };
+}
+
+describe('parseUsageCollection', () => {
+ it.todo('throws when a function is returned from fetch');
+ it.todo('throws when an object is not returned from fetch');
+
+ it('throws when mapping fields is not defined', () => {
+ const { program, sourceFile } = loadFixtureProgram('unmapped_collector');
+ expect(() => [...parseUsageCollection(sourceFile, program)]).toThrowErrorMatchingSnapshot();
+ });
+
+ it('parses root level defined collector', () => {
+ const { program, sourceFile } = loadFixtureProgram('working_collector');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual([parsedWorkingCollector]);
+ });
+
+ it('parses nested collectors', () => {
+ const { program, sourceFile } = loadFixtureProgram('nested_collector');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual([parsedNestedCollector]);
+ });
+
+ it('parses imported schema property', () => {
+ const { program, sourceFile } = loadFixtureProgram('imported_schema');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual(parsedImportedSchemaCollector);
+ });
+
+ it('parses externally defined collectors', () => {
+ const { program, sourceFile } = loadFixtureProgram('externally_defined_collector');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual(parsedExternallyDefinedCollector);
+ });
+
+ it('parses imported Usage interface', () => {
+ const { program, sourceFile } = loadFixtureProgram('imported_usage_interface');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual(parsedImportedUsageInterface);
+ });
+
+ it('skips files that do not define a collector', () => {
+ const { program, sourceFile } = loadFixtureProgram('file_with_no_collector');
+ const result = [...parseUsageCollection(sourceFile, program)];
+ expect(result).toEqual([]);
+ });
+});
diff --git a/packages/kbn-telemetry-tools/src/tools/ts_parser.ts b/packages/kbn-telemetry-tools/src/tools/ts_parser.ts
new file mode 100644
index 00000000000000..6af8450f5a2e8c
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/ts_parser.ts
@@ -0,0 +1,210 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import { createFailError } from '@kbn/dev-utils';
+import * as path from 'path';
+import { getProperty, getPropertyValue } from './utils';
+import { getDescriptor, Descriptor } from './serializer';
+
+export function* traverseNodes(maybeNodes: ts.Node | ts.Node[]): Generator {
+ const nodes: ts.Node[] = Array.isArray(maybeNodes) ? maybeNodes : [maybeNodes];
+
+ for (const node of nodes) {
+ const children: ts.Node[] = [];
+ yield node;
+ ts.forEachChild(node, (child) => {
+ children.push(child);
+ });
+ for (const child of children) {
+ yield* traverseNodes(child);
+ }
+ }
+}
+
+export function isMakeUsageCollectorFunction(
+ node: ts.Node,
+ sourceFile: ts.SourceFile
+): node is ts.CallExpression {
+ if (ts.isCallExpression(node)) {
+ const isMakeUsageCollector = /makeUsageCollector$/.test(node.expression.getText(sourceFile));
+ if (isMakeUsageCollector) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+export interface CollectorDetails {
+ collectorName: string;
+ fetch: { typeName: string; typeDescriptor: Descriptor };
+ schema: { value: any };
+}
+
+function getCollectionConfigNode(
+ collectorNode: ts.CallExpression,
+ sourceFile: ts.SourceFile
+): ts.Expression {
+ if (collectorNode.arguments.length > 1) {
+ throw Error(`makeUsageCollector does not accept more than one argument.`);
+ }
+ const collectorConfig = collectorNode.arguments[0];
+
+ if (ts.isObjectLiteralExpression(collectorConfig)) {
+ return collectorConfig;
+ }
+
+ const variableDefintionName = collectorConfig.getText();
+ for (const node of traverseNodes(sourceFile)) {
+ if (ts.isVariableDeclaration(node)) {
+ const declarationName = node.name.getText();
+ if (declarationName === variableDefintionName) {
+ if (!node.initializer) {
+ throw Error(`Unable to parse collector configs.`);
+ }
+ if (ts.isObjectLiteralExpression(node.initializer)) {
+ return node.initializer;
+ }
+ if (ts.isCallExpression(node.initializer)) {
+ const functionName = node.initializer.expression.getText(sourceFile);
+ for (const sfNode of traverseNodes(sourceFile)) {
+ if (ts.isFunctionDeclaration(sfNode)) {
+ const fnDeclarationName = sfNode.name?.getText();
+ if (fnDeclarationName === functionName) {
+ const returnStatements: ts.ReturnStatement[] = [];
+ for (const fnNode of traverseNodes(sfNode)) {
+ if (ts.isReturnStatement(fnNode) && fnNode.parent === sfNode.body) {
+ returnStatements.push(fnNode);
+ }
+ }
+
+ if (returnStatements.length > 1) {
+ throw Error(`Collector function cannot have multiple return statements.`);
+ }
+ if (returnStatements.length === 0) {
+ throw Error(`Collector function must have a return statement.`);
+ }
+ if (!returnStatements[0].expression) {
+ throw Error(`Collector function return statement must be an expression.`);
+ }
+
+ return returnStatements[0].expression;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ throw Error(`makeUsageCollector argument must be an object.`);
+}
+
+function extractCollectorDetails(
+ collectorNode: ts.CallExpression,
+ program: ts.Program,
+ sourceFile: ts.SourceFile
+): CollectorDetails {
+ if (collectorNode.arguments.length > 1) {
+ throw Error(`makeUsageCollector does not accept more than one argument.`);
+ }
+
+ const collectorConfig = getCollectionConfigNode(collectorNode, sourceFile);
+
+ const typeProperty = getProperty(collectorConfig, 'type');
+ if (!typeProperty) {
+ throw Error(`usageCollector.type must be defined.`);
+ }
+ const typePropertyValue = getPropertyValue(typeProperty, program);
+ if (!typePropertyValue || typeof typePropertyValue !== 'string') {
+ throw Error(`usageCollector.type must be be a non-empty string literal.`);
+ }
+
+ const fetchProperty = getProperty(collectorConfig, 'fetch');
+ if (!fetchProperty) {
+ throw Error(`usageCollector.fetch must be defined.`);
+ }
+ const schemaProperty = getProperty(collectorConfig, 'schema');
+ if (!schemaProperty) {
+ throw Error(`usageCollector.schema must be defined.`);
+ }
+
+ const schemaPropertyValue = getPropertyValue(schemaProperty, program, { chaseImport: true });
+ if (!schemaPropertyValue || typeof schemaPropertyValue !== 'object') {
+ throw Error(`usageCollector.schema must be be an object.`);
+ }
+
+ const collectorNodeType = collectorNode.typeArguments;
+ if (!collectorNodeType || collectorNodeType?.length === 0) {
+ throw Error(`makeUsageCollector requires a Usage type makeUsageCollector({ ... }).`);
+ }
+
+ const usageTypeNode = collectorNodeType[0];
+ const usageTypeName = usageTypeNode.getText();
+ const usageType = getDescriptor(usageTypeNode, program) as Descriptor;
+
+ return {
+ collectorName: typePropertyValue,
+ schema: {
+ value: schemaPropertyValue,
+ },
+ fetch: {
+ typeName: usageTypeName,
+ typeDescriptor: usageType,
+ },
+ };
+}
+
+export function sourceHasUsageCollector(sourceFile: ts.SourceFile) {
+ if (sourceFile.isDeclarationFile === true || (sourceFile as any).identifierCount === 0) {
+ return false;
+ }
+
+ const identifiers = (sourceFile as any).identifiers;
+ if (
+ (!identifiers.get('makeUsageCollector') && !identifiers.get('type')) ||
+ !identifiers.get('fetch')
+ ) {
+ return false;
+ }
+
+ return true;
+}
+
+export type ParsedUsageCollection = [string, CollectorDetails];
+
+export function* parseUsageCollection(
+ sourceFile: ts.SourceFile,
+ program: ts.Program
+): Generator {
+ const relativePath = path.relative(process.cwd(), sourceFile.fileName);
+ if (sourceHasUsageCollector(sourceFile)) {
+ for (const node of traverseNodes(sourceFile)) {
+ if (isMakeUsageCollectorFunction(node, sourceFile)) {
+ try {
+ const collectorDetails = extractCollectorDetails(node, program, sourceFile);
+ yield [relativePath, collectorDetails];
+ } catch (err) {
+ throw createFailError(`Error extracting collector in ${relativePath}\n${err}`);
+ }
+ }
+ }
+ }
+}
diff --git a/packages/kbn-telemetry-tools/src/tools/utils.ts b/packages/kbn-telemetry-tools/src/tools/utils.ts
new file mode 100644
index 00000000000000..f5cf74ae35e456
--- /dev/null
+++ b/packages/kbn-telemetry-tools/src/tools/utils.ts
@@ -0,0 +1,238 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import * as ts from 'typescript';
+import * as _ from 'lodash';
+import * as path from 'path';
+import glob from 'glob';
+import { readFile, writeFile } from 'fs';
+import { promisify } from 'util';
+import normalize from 'normalize-path';
+import { Optional } from '@kbn/utility-types';
+
+export const readFileAsync = promisify(readFile);
+export const writeFileAsync = promisify(writeFile);
+export const globAsync = promisify(glob);
+
+export function isPropertyWithKey(property: ts.Node, identifierName: string) {
+ if (ts.isPropertyAssignment(property) || ts.isMethodDeclaration(property)) {
+ if (ts.isIdentifier(property.name)) {
+ return property.name.text === identifierName;
+ }
+ }
+
+ return false;
+}
+
+export function getProperty(objectNode: any, propertyName: string): ts.Node | null {
+ let foundProperty = null;
+ ts.visitNodes(objectNode?.properties || [], (node) => {
+ if (isPropertyWithKey(node, propertyName)) {
+ foundProperty = node;
+ return node;
+ }
+ });
+
+ return foundProperty;
+}
+
+export function getModuleSpecifier(node: ts.Node): string {
+ if ((node as any).moduleSpecifier) {
+ return (node as any).moduleSpecifier.text;
+ }
+ return getModuleSpecifier(node.parent);
+}
+
+export function getIdentifierDeclarationFromSource(node: ts.Node, source: ts.SourceFile) {
+ if (!ts.isIdentifier(node)) {
+ throw new Error(`node is not an identifier ${node.getText()}`);
+ }
+
+ const identifierName = node.getText();
+ const identifierDefinition: ts.Node = (source as any).locals.get(identifierName);
+ if (!identifierDefinition) {
+ throw new Error(`Unable to fine identifier in source ${identifierName}`);
+ }
+ const declarations = (identifierDefinition as any).declarations as ts.Node[];
+
+ const latestDeclaration: ts.Node | false | undefined =
+ Array.isArray(declarations) && declarations[declarations.length - 1];
+ if (!latestDeclaration) {
+ throw new Error(`Unable to fine declaration for identifier ${identifierName}`);
+ }
+
+ return latestDeclaration;
+}
+
+export function getIdentifierDeclaration(node: ts.Node) {
+ const source = node.getSourceFile();
+ if (!source) {
+ throw new Error('Unable to get source from node; check program configs.');
+ }
+
+ return getIdentifierDeclarationFromSource(node, source);
+}
+
+export function getVariableValue(node: ts.Node): string | Record {
+ if (ts.isStringLiteral(node) || ts.isNumericLiteral(node)) {
+ return node.text;
+ }
+
+ if (ts.isObjectLiteralExpression(node)) {
+ return serializeObject(node);
+ }
+
+ throw Error(`Unsuppored Node: cannot get value of node (${node.getText()}) of kind ${node.kind}`);
+}
+
+export function serializeObject(node: ts.Node) {
+ if (!ts.isObjectLiteralExpression(node)) {
+ throw new Error(`Expecting Object literal Expression got ${node.getText()}`);
+ }
+
+ const value: Record = {};
+ for (const property of node.properties) {
+ const propertyName = property.name?.getText();
+ if (typeof propertyName === 'undefined') {
+ throw new Error(`Unable to get property name ${property.getText()}`);
+ }
+ if (ts.isPropertyAssignment(property)) {
+ value[propertyName] = getVariableValue(property.initializer);
+ } else {
+ value[propertyName] = getVariableValue(property);
+ }
+ }
+
+ return value;
+}
+
+export function getResolvedModuleSourceFile(
+ originalSource: ts.SourceFile,
+ program: ts.Program,
+ importedModuleName: string
+) {
+ const resolvedModule = (originalSource as any).resolvedModules.get(importedModuleName);
+ const resolvedModuleSourceFile = program.getSourceFile(resolvedModule.resolvedFileName);
+ if (!resolvedModuleSourceFile) {
+ throw new Error(`Unable to find resolved module ${importedModuleName}`);
+ }
+ return resolvedModuleSourceFile;
+}
+
+export function getPropertyValue(
+ node: ts.Node,
+ program: ts.Program,
+ config: Optional<{ chaseImport: boolean }> = {}
+) {
+ const { chaseImport = false } = config;
+
+ if (ts.isPropertyAssignment(node)) {
+ const { initializer } = node;
+
+ if (ts.isIdentifier(initializer)) {
+ const identifierName = initializer.getText();
+ const declaration = getIdentifierDeclaration(initializer);
+ if (ts.isImportSpecifier(declaration)) {
+ if (!chaseImport) {
+ throw new Error(
+ `Value of node ${identifierName} is imported from another file. Chasing imports is not allowed.`
+ );
+ }
+
+ const importedModuleName = getModuleSpecifier(declaration);
+
+ const source = node.getSourceFile();
+ const declarationSource = getResolvedModuleSourceFile(source, program, importedModuleName);
+ const declarationNode = getIdentifierDeclarationFromSource(initializer, declarationSource);
+ if (!ts.isVariableDeclaration(declarationNode)) {
+ throw new Error(`Expected ${identifierName} to be variable declaration.`);
+ }
+ if (!declarationNode.initializer) {
+ throw new Error(`Expected ${identifierName} to be initialized.`);
+ }
+ const serializedObject = serializeObject(declarationNode.initializer);
+ return serializedObject;
+ }
+
+ return getVariableValue(declaration);
+ }
+
+ return getVariableValue(initializer);
+ }
+}
+
+export function pickDeep(collection: any, identity: any, thisArg?: any) {
+ const picked: any = _.pick(collection, identity, thisArg);
+ const collections = _.pick(collection, _.isObject, thisArg);
+
+ _.each(collections, function (item, key) {
+ let object;
+ if (_.isArray(item)) {
+ object = _.reduce(
+ item,
+ function (result, value) {
+ const pickedDeep = pickDeep(value, identity, thisArg);
+ if (!_.isEmpty(pickedDeep)) {
+ result.push(pickedDeep);
+ }
+ return result;
+ },
+ [] as any[]
+ );
+ } else {
+ object = pickDeep(item, identity, thisArg);
+ }
+
+ if (!_.isEmpty(object)) {
+ picked[key || ''] = object;
+ }
+ });
+
+ return picked;
+}
+
+export const flattenKeys = (obj: any, keyPath: any[] = []): any => {
+ if (_.isObject(obj)) {
+ return _.reduce(
+ obj,
+ (cum, next, key) => {
+ const keys = [...keyPath, key];
+ return _.merge(cum, flattenKeys(next, keys));
+ },
+ {}
+ );
+ }
+ return { [keyPath.join('.')]: obj };
+};
+
+export function difference(actual: any, expected: any) {
+ function changes(obj: any, base: any) {
+ return _.transform(obj, function (result, value, key) {
+ if (key && !_.isEqual(value, base[key])) {
+ result[key] =
+ _.isObject(value) && _.isObject(base[key]) ? changes(value, base[key]) : value;
+ }
+ });
+ }
+ return changes(actual, expected);
+}
+
+export function normalizePath(inputPath: string) {
+ return normalize(path.relative('.', inputPath));
+}
diff --git a/packages/kbn-telemetry-tools/tsconfig.json b/packages/kbn-telemetry-tools/tsconfig.json
new file mode 100644
index 00000000000000..13ce8ef2bad60b
--- /dev/null
+++ b/packages/kbn-telemetry-tools/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": [
+ "src/**/*",
+ ]
+}
diff --git a/scripts/backport.js b/scripts/backport.js
index 64cd5721834ead..2094534e2c4b39 100644
--- a/scripts/backport.js
+++ b/scripts/backport.js
@@ -18,4 +18,5 @@
*/
require('../src/setup_node_env/node_version_validator');
-require('backport');
+var backport = require('backport');
+backport.run();
diff --git a/scripts/telemetry_check.js b/scripts/telemetry_check.js
new file mode 100644
index 00000000000000..06b3ed46bdba6a
--- /dev/null
+++ b/scripts/telemetry_check.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+require('../src/setup_node_env/prebuilt_dev_only_entry');
+require('@kbn/telemetry-tools').runTelemetryCheck();
diff --git a/scripts/telemetry_extract.js b/scripts/telemetry_extract.js
new file mode 100644
index 00000000000000..051bee26537b9b
--- /dev/null
+++ b/scripts/telemetry_extract.js
@@ -0,0 +1,21 @@
+/*
+ * Licensed to Elasticsearch B.V. under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch B.V. licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+require('../src/setup_node_env/prebuilt_dev_only_entry');
+require('@kbn/telemetry-tools').runTelemetryExtract();
diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx
index 95361d8287c716..d7f15decb255dd 100644
--- a/src/core/public/application/application_service.tsx
+++ b/src/core/public/application/application_service.tsx
@@ -201,6 +201,7 @@ export class ApplicationService {
this.mounters.set(app.id, {
appRoute: app.appRoute!,
appBasePath: basePath.prepend(app.appRoute!),
+ exactRoute: app.exactRoute ?? false,
mount: wrapMount(plugin, app),
unmountBeforeMounting: false,
legacy: false,
@@ -236,6 +237,7 @@ export class ApplicationService {
this.mounters.set(app.id, {
appRoute,
appBasePath,
+ exactRoute: false,
mount,
unmountBeforeMounting: true,
legacy: true,
diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx
index 2827b93f6d17e5..f992e121437a96 100644
--- a/src/core/public/application/integration_tests/router.test.tsx
+++ b/src/core/public/application/integration_tests/router.test.tsx
@@ -30,7 +30,6 @@ import { ScopedHistory } from '../scoped_history';
describe('AppRouter', () => {
let mounters: MockedMounterMap;
let globalHistory: History;
- let appStatuses$: BehaviorSubject